diff --git a/.gitignore b/.gitignore index c318eebe2..0bf0b0de5 100644 --- a/.gitignore +++ b/.gitignore @@ -205,4 +205,10 @@ fabric.properties # End of https://www.toptal.com/developers/gitignore/api/rider .idea -.fake \ No newline at end of file +.fake +/nbproject/ +/*/*/*/*.a +/*/*/*/*/*/*/*/*.o +/*/*/*/*/*/*/*/*/*.o +/*/*/*/*/*/*/*/*/*/*.o +/*/*/*/*/*/*/*/*/*/*.o diff --git a/examples/conceal_pool.json b/examples/conceal_pool.json new file mode 100644 index 000000000..dd9551962 --- /dev/null +++ b/examples/conceal_pool.json @@ -0,0 +1,143 @@ +{ + "logging": { + "level": "info", + "enableConsoleLog": true, + "enableConsoleColors": true, + "logFile": "", + "apiLogFile": "", + "logBaseDirectory": "", + "perPoolLogFile": false + }, + "banning": { + "manager": "Integrated", + "banOnJunkReceive": true, + "banOnInvalidShares": false + }, + "notifications": { + "enabled": false, + "email": { + "host": "smtp.example.com", + "port": 587, + "user": "user", + "password": "password", + "fromAddress": "info@yourpool.org", + "fromName": "pool support" + }, + "admin": { + "enabled": false, + "emailAddress": "user@example.com", + "notifyBlockFound": true + } + }, + "persistence": { + "postgres": { + "host": "127.0.0.1", + "port": 5432, + "user": "miningcore", + "password": "password", + "database": "miningcore" + } + }, + "paymentProcessing": { + "enabled": true, + "interval": 600, + "shareRecoveryFile": "recovered-shares.txt" + }, + "api": { + "enabled": true, + "listenAddress": "*", + "port": 4000, + "metricsIpWhitelist": [], + "rateLimiting": { + "disabled": true, + "rules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 5 + } + ], + "ipWhitelist": [ + "" + ] + } + }, + "pools": [ + { + "id": "ccx1", + "enabled": true, + "coin": "conceal", + "networkTypeOverride": "mainnet", + "cryptonightMaxThreads": 1, + "address": "ccx7BRXk4eubahkPNe4mmZ1PYwigPmqGT5ciBWib39aQQjWctY6vzA7RuBBkcoSKxEVBQArdvJi5YhEHRY29sSpS9EiD5c2nW5", + "rewardRecipients": [ + { + "type": "op", + "address": "ccx7BRXk4eubahkPNe4mmZ1PYwigPmqGT5ciBWib39aQQjWctY6vzA7RuBBkcoSKxEVBQArdvJi5YhEHRY29sSpS9EiD5c2nW5", + "percentage": 0.1 + } + ], + "blockRefreshInterval": 250, + "jobRebroadcastTimeout": 3, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3364": { + "listenAddress": "0.0.0.0", + "difficulty": 5000, + "varDiff": { + "minDiff": 2500, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + }, + "3365": { + "listenAddress": "0.0.0.0", + "difficulty": 5000, + "tls": true, + "tlsPfxFile": "", + "tlsPfxPassword": "password", + "varDiff": { + "minDiff": 2500, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30, + "maxDelta": 500 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 16600, + "user": null, + "password": null + }, + { + "host": "127.0.0.1", + "port": 8770, + "user": null, + "password": null, + "category": "wallet" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 0.1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + } + ] +} \ No newline at end of file diff --git a/examples/ethereumclassic_pool.json b/examples/ethereumclassic_pool.json new file mode 100644 index 000000000..431034714 --- /dev/null +++ b/examples/ethereumclassic_pool.json @@ -0,0 +1,126 @@ +{ + "logging": { + "level": "info", + "enableConsoleLog": true, + "enableConsoleColors": true, + "logFile": "", + "apiLogFile": "", + "logBaseDirectory": "", + "perPoolLogFile": false + }, + "banning": { + "manager": "Integrated", + "banOnJunkReceive": false, + "banOnInvalidShares": false + }, + "notifications": { + "enabled": false, + "email": { + "host": "smtp.example.com", + "port": 587, + "user": "user", + "password": "password", + "fromAddress": "info@yourpool.org", + "fromName": "pool support" + }, + "admin": { + "enabled": false, + "emailAddress": "user@example.com", + "notifyBlockFound": true + } + }, + "persistence": { + "postgres": { + "host": "127.0.0.1", + "port": 5432, + "user": "miningcore", + "password": "password", + "database": "miningcore" + } + }, + "paymentProcessing": { + "enabled": true, + "interval": 100, + "shareRecoveryFile": "recovered-shares.txt" + }, + "api": { + "enabled": true, + "listenAddress": "*", + "port": 4000, + "metricsIpWhitelist": [], + "rateLimiting": { + "disabled": true, + "rules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 5 + } + ], + "ipWhitelist": [ + "" + ] + } + }, + "clusterName": "eu1", + "pools": [ + { + "id": "etc1", + "enabled": true, + "coin": "ethereumclassic", + "address": "0x421Afb2ce225D3A2d3DD6e63Fe57E124B40e20Af", + "rewardRecipients": [ + { + "type": "op", + "address": "0x421Afb2ce225D3A2d3DD6e63Fe57E124B40e20Af", + "percentage": 1.0 + } + ], + "blockRefreshInterval": 120, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "4073": { + "name": "GPU-SMALL", + "listenAddress": "*", + "difficulty": 0.1, + "varDiff": { + "minDiff": 0.1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30 + } + } + }, + "chainTypeOverride": "Classic", + "dagDir": "", + "daemons": [ + { + "host": "127.0.0.1", + "port": 8545, + "user": "", + "password": "" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 0.1, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + }, + "gas": 21000, + "maxFeePerGas": 50000000000, + "BlockSearchOffset": 100, + "keepUncles": false, + "keepTransactionFees": false + } + } + ] +} diff --git a/examples/ubiq_pool.json b/examples/ubiq_pool.json new file mode 100644 index 000000000..81a001a35 --- /dev/null +++ b/examples/ubiq_pool.json @@ -0,0 +1,126 @@ +{ + "logging": { + "level": "info", + "enableConsoleLog": true, + "enableConsoleColors": true, + "logFile": "", + "apiLogFile": "", + "logBaseDirectory": "", + "perPoolLogFile": false + }, + "banning": { + "manager": "Integrated", + "banOnJunkReceive": false, + "banOnInvalidShares": false + }, + "notifications": { + "enabled": false, + "email": { + "host": "smtp.example.com", + "port": 587, + "user": "user", + "password": "password", + "fromAddress": "info@yourpool.org", + "fromName": "pool support" + }, + "admin": { + "enabled": false, + "emailAddress": "user@example.com", + "notifyBlockFound": true + } + }, + "persistence": { + "postgres": { + "host": "127.0.0.1", + "port": 5432, + "user": "miningcore", + "password": "password", + "database": "miningcore" + } + }, + "paymentProcessing": { + "enabled": true, + "interval": 100, + "shareRecoveryFile": "recovered-shares.txt" + }, + "api": { + "enabled": true, + "listenAddress": "*", + "port": 4000, + "metricsIpWhitelist": [], + "rateLimiting": { + "disabled": true, + "rules": [ + { + "Endpoint": "*", + "Period": "1s", + "Limit": 5 + } + ], + "ipWhitelist": [ + "" + ] + } + }, + "clusterName": "eu1", + "pools": [ + { + "id": "ubq1", + "enabled": true, + "coin": "ubiq", + "address": "0x6101Ee22AB2cd3907E5CA0b70EF12A2afE842A56", + "rewardRecipients": [ + { + "type": "op", + "address": "0x6101Ee22AB2cd3907E5CA0b70EF12A2afE842A56", + "percentage": 1.0 + } + ], + "blockRefreshInterval": 120, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "4073": { + "name": "GPU-SMALL", + "listenAddress": "*", + "difficulty": 0.1, + "varDiff": { + "minDiff": 0.1, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 30 + } + } + }, + "chainTypeOverride": "Ubiq", + "dagDir": "", + "daemons": [ + { + "host": "127.0.0.1", + "port": 8588, + "user": "", + "password": "" + } + ], + "paymentProcessing": { + "enabled": true, + "minimumPayment": 0.5, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + }, + "gas": 21000, + "maxFeePerGas": 80000000000, + "BlockSearchOffset": 100, + "keepUncles": false, + "keepTransactionFees": false + } + } + ] +} diff --git a/src/Miningcore/AutofacModule.cs b/src/Miningcore/AutofacModule.cs index 8b70800ad..ef2b595b9 100644 --- a/src/Miningcore/AutofacModule.cs +++ b/src/Miningcore/AutofacModule.cs @@ -3,6 +3,7 @@ using Miningcore.Api; using Miningcore.Banning; using Miningcore.Blockchain.Bitcoin; +using Miningcore.Blockchain.Conceal; using Miningcore.Blockchain.Cryptonote; using Miningcore.Blockchain.Equihash; using Miningcore.Blockchain.Ethereum; @@ -147,7 +148,12 @@ protected override void Load(ContainerBuilder builder) // Bitcoin and family builder.RegisterType(); + + ////////////////////// + // Conceal + builder.RegisterType(); + ////////////////////// // Cryptonote diff --git a/src/Miningcore/Blockchain/Conceal/ConcealConstants.cs b/src/Miningcore/Blockchain/Conceal/ConcealConstants.cs new file mode 100644 index 000000000..d4237a065 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/ConcealConstants.cs @@ -0,0 +1,60 @@ +using System.Globalization; +using System.Text.RegularExpressions; +using Org.BouncyCastle.Math; + +namespace Miningcore.Blockchain.Conceal; + +public enum ConcealNetworkType +{ + Main = 1, + Test +} + +public static class ConcealConstants +{ + public const string WalletDaemonCategory = "wallet"; + + public const string DaemonRpcLocation = "json_rpc"; + public const string DaemonRpcGetInfoLocation = "getinfo"; + public const int ConcealRpcMethodNotFound = -32601; + public const int PaymentIdHexLength = 64; + public const decimal SmallestUnit = 1000000; + public static readonly Regex RegexValidNonce = new("^[0-9a-f]{8}$", RegexOptions.Compiled); + + public static readonly BigInteger Diff1 = new("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", 16); + public static readonly System.Numerics.BigInteger Diff1b = System.Numerics.BigInteger.Parse("00FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", NumberStyles.HexNumber); + + public const int PayoutMinBlockConfirmations = 10; + + public const int InstanceIdSize = 4; + public const int ExtraNonceSize = 4; + + // NOTE: for whatever strange reason only reserved_size -1 can be used, + // the LAST byte MUST be zero or nothing works + public const int ReserveSize = ExtraNonceSize + InstanceIdSize + 1; + + // Offset to nonce in block blob + public const int BlobNonceOffset = 39; + + public const decimal StaticTransactionFeeReserve = 0.001m; // in conceal +} + +public static class ConcealCommands +{ + public const string GetInfo = "getinfo"; + public const string GetLastBlockHeader = "getlastblockheader"; + public const string GetBlockTemplate = "getblocktemplate"; + public const string SubmitBlock = "submitblock"; + public const string GetBlockHeaderByHash = "getblockheaderbyhash"; + public const string GetBlockHeaderByHeight = "getblockheaderbyheight"; +} + +public static class ConcealWalletCommands +{ + public const string GetBalance = "getBalance"; + public const string GetAddress = "getAddresses"; + public const string SendTransaction = "sendTransaction"; + public const string GetTransactions = "getTransactions"; + public const string SplitIntegratedAddress = "splitIntegrated"; + public const string Save = "save"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/ConcealJob.cs b/src/Miningcore/Blockchain/Conceal/ConcealJob.cs new file mode 100644 index 000000000..c37df5618 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/ConcealJob.cs @@ -0,0 +1,192 @@ +using Miningcore.Blockchain.Conceal.DaemonResponses; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.Native; +using Miningcore.Stratum; +using Miningcore.Util; +using Org.BouncyCastle.Math; +using static Miningcore.Native.Cryptonight.Algorithm; +using Contract = Miningcore.Contracts.Contract; + +namespace Miningcore.Blockchain.Conceal; + +public class ConcealJob +{ + public ConcealJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, string jobId, + ConcealCoinTemplate coin, PoolConfig poolConfig, ClusterConfig clusterConfig, string prevHash) + { + Contract.RequiresNonNull(blockTemplate); + Contract.RequiresNonNull(poolConfig); + Contract.RequiresNonNull(clusterConfig); + Contract.RequiresNonNull(instanceId); + Contract.Requires(!string.IsNullOrEmpty(jobId)); + + BlockTemplate = blockTemplate; + PrepareBlobTemplate(instanceId); + PrevHash = prevHash; + + hashFunc = hashFuncs[coin.Hash]; + } + + protected delegate void HashFunc(ReadOnlySpan data, Span result, ulong height); + + protected static readonly Dictionary hashFuncs = new() + { + { CryptonightHashType.CryptonightCCX, (data, result, height) => Cryptonight.CryptonightHash(data, result, CN_CCX, height) }, + { CryptonightHashType.CryptonightGPU, (data, result, height) => Cryptonight.CryptonightHash(data, result, CN_GPU, height) }, + }; + + private byte[] blobTemplate; + private int extraNonce; + private readonly HashFunc hashFunc; + + private void PrepareBlobTemplate(byte[] instanceId) + { + blobTemplate = BlockTemplate.Blob.HexToByteArray(); + + // inject instanceId + instanceId.CopyTo(blobTemplate, BlockTemplate.ReservedOffset + ConcealConstants.ExtraNonceSize); + } + + private string EncodeBlob(uint workerExtraNonce) + { + Span blob = stackalloc byte[blobTemplate.Length]; + blobTemplate.CopyTo(blob); + + // inject extranonce (big-endian) at the beginning of the reserved area + var bytes = BitConverter.GetBytes(workerExtraNonce.ToBigEndian()); + bytes.CopyTo(blob[BlockTemplate.ReservedOffset..]); + + return CryptonoteBindings.ConvertBlob(blob, blobTemplate.Length).ToHexString(); + } + + private string EncodeTarget(double difficulty, int size = 4) + { + var diff = BigInteger.ValueOf((long) (difficulty * 255d)); + var quotient = ConcealConstants.Diff1.Divide(diff).Multiply(BigInteger.ValueOf(255)); + var bytes = quotient.ToByteArray().AsSpan(); + Span padded = stackalloc byte[32]; + + var padLength = padded.Length - bytes.Length; + + if(padLength > 0) + bytes.CopyTo(padded.Slice(padLength, bytes.Length)); + + padded = padded[..size]; + padded.Reverse(); + + return padded.ToHexString(); + } + + private void ComputeBlockHash(ReadOnlySpan blobConverted, Span result) + { + // blockhash is computed from the converted blob data prefixed with its length + Span block = stackalloc byte[blobConverted.Length + 1]; + block[0] = (byte) blobConverted.Length; + blobConverted.CopyTo(block[1..]); + + CryptonoteBindings.CryptonightHashFast(block, result); + } + + #region API-Surface + + public string PrevHash { get; } + public GetBlockTemplateResponse BlockTemplate { get; } + + public void PrepareWorkerJob(ConcealWorkerJob workerJob, out string blob, out string target) + { + workerJob.Height = BlockTemplate.Height; + workerJob.ExtraNonce = (uint) Interlocked.Increment(ref extraNonce); + + if(extraNonce < 0) + extraNonce = 0; + + blob = EncodeBlob(workerJob.ExtraNonce); + target = EncodeTarget(workerJob.Difficulty); + } + + public (Share Share, string BlobHex) ProcessShare(string nonce, uint workerExtraNonce, string workerHash, StratumConnection worker) + { + Contract.Requires(!string.IsNullOrEmpty(nonce)); + Contract.Requires(!string.IsNullOrEmpty(workerHash)); + Contract.Requires(workerExtraNonce != 0); + + var context = worker.ContextAs(); + + // validate nonce + if(!ConcealConstants.RegexValidNonce.IsMatch(nonce)) + throw new StratumException(StratumError.MinusOne, "malformed nonce"); + + // clone template + Span blob = stackalloc byte[blobTemplate.Length]; + blobTemplate.CopyTo(blob); + + // inject extranonce + var bytes = BitConverter.GetBytes(workerExtraNonce.ToBigEndian()); + bytes.CopyTo(blob[BlockTemplate.ReservedOffset..]); + + // inject nonce + bytes = nonce.HexToByteArray(); + bytes.CopyTo(blob[ConcealConstants.BlobNonceOffset..]); + + // convert + var blobConverted = CryptonoteBindings.ConvertBlob(blob, blobTemplate.Length); + if(blobConverted == null) + throw new StratumException(StratumError.MinusOne, "malformed blob"); + + // hash it + Span headerHash = stackalloc byte[32]; + hashFunc(blobConverted, headerHash, BlockTemplate.Height); + + var headerHashString = headerHash.ToHexString(); + if(headerHashString != workerHash) + throw new StratumException(StratumError.MinusOne, "bad hash"); + + // check difficulty + var headerValue = headerHash.ToBigInteger(); + var shareDiff = (double) new BigRational(ConcealConstants.Diff1b, headerValue); + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + var isBlockCandidate = shareDiff >= BlockTemplate.Difficulty; + + // test if share meets at least workers current difficulty + if(!isBlockCandidate && ratio < 0.99) + { + // check if share matched the previous difficulty from before a vardiff retarget + if(context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue) + { + ratio = shareDiff / context.PreviousDifficulty.Value; + + if(ratio < 0.99) + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + + // use previous difficulty + stratumDifficulty = context.PreviousDifficulty.Value; + } + + else + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + } + + var result = new Share + { + BlockHeight = BlockTemplate.Height, + Difficulty = stratumDifficulty, + }; + + if(isBlockCandidate) + { + // Compute block hash + Span blockHash = stackalloc byte[32]; + ComputeBlockHash(blobConverted, blockHash); + + // Fill in block-relevant fields + result.IsBlockCandidate = true; + result.BlockHash = blockHash.ToHexString(); + } + + return (result, blob.ToHexString()); + } + + #endregion // API-Surface +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs b/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs new file mode 100644 index 000000000..c043a4044 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/ConcealJobManager.cs @@ -0,0 +1,676 @@ +using static System.Array; +using System.Globalization; +using System.Reactive; +using System.Reactive.Linq; +using System.Security.Cryptography; +using System.Text; +using Autofac; +using Miningcore.Blockchain.Bitcoin; +using Miningcore.Blockchain.Conceal.Configuration; +using Miningcore.Blockchain.Conceal.DaemonRequests; +using Miningcore.Blockchain.Conceal.DaemonResponses; +using Miningcore.Blockchain.Conceal.StratumRequests; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.JsonRpc; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Native; +using Miningcore.Notifications.Messages; +using Miningcore.Rest; +using Miningcore.Rpc; +using Miningcore.Stratum; +using Miningcore.Time; +using Miningcore.Util; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using NLog; +using Contract = Miningcore.Contracts.Contract; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Conceal; + +public class ConcealJobManager : JobManagerBase +{ + public ConcealJobManager( + IComponentContext ctx, + IMasterClock clock, + IHttpClientFactory httpClientFactory, + IMessageBus messageBus) : + base(ctx, messageBus) + { + Contract.RequiresNonNull(ctx); + Contract.RequiresNonNull(clock); + Contract.RequiresNonNull(messageBus); + + this.clock = clock; + this.httpClientFactory = httpClientFactory; + } + + private byte[] instanceId; + private DaemonEndpointConfig[] daemonEndpoints; + private IHttpClientFactory httpClientFactory; + private SimpleRestClient restClient; + private RpcClient rpc; + private RpcClient walletRpc; + private readonly IMasterClock clock; + private ConcealNetworkType networkType; + private ConcealPoolConfigExtra extraPoolConfig; + private ulong poolAddressBase58Prefix; + private DaemonEndpointConfig[] walletDaemonEndpoints; + private ConcealCoinTemplate coin; + + protected async Task UpdateJob(CancellationToken ct, string via = null, string json = null) + { + try + { + var response = string.IsNullOrEmpty(json) ? await GetBlockTemplateAsync(ct) : GetBlockTemplateFromJson(json); + + // may happen if daemon is currently not connected to peers + if(response.Error != null) + { + logger.Warn(() => $"Unable to update job. Daemon responded with: {response.Error.Message} Code {response.Error.Code}"); + return false; + } + + var blockTemplate = response.Response; + var job = currentJob; + var newHash = blockTemplate.Blob.HexToByteArray().AsSpan().Slice(7, 32).ToHexString(); + + var isNew = job == null || newHash != job.PrevHash; + + if(isNew) + { + messageBus.NotifyChainHeight(poolConfig.Id, blockTemplate.Height, poolConfig.Template); + + if(via != null) + logger.Info(() => $"Detected new block {blockTemplate.Height} [{via}]"); + else + logger.Info(() => $"Detected new block {blockTemplate.Height}"); + + // init job + job = new ConcealJob(blockTemplate, instanceId, NextJobId(), coin, poolConfig, clusterConfig, newHash); + currentJob = job; + + // update stats + BlockchainStats.LastNetworkBlockTime = clock.Now; + BlockchainStats.BlockHeight = job.BlockTemplate.Height; + BlockchainStats.NetworkDifficulty = job.BlockTemplate.Difficulty; + BlockchainStats.NextNetworkTarget = ""; + BlockchainStats.NextNetworkBits = ""; + } + + else + { + if(via != null) + logger.Debug(() => $"Template update {blockTemplate.Height} [{via}]"); + else + logger.Debug(() => $"Template update {blockTemplate.Height}"); + } + + return isNew; + } + + catch(OperationCanceledException) + { + // ignored + } + + catch(Exception ex) + { + logger.Error(ex, () => $"Error during {nameof(UpdateJob)}"); + } + + return false; + } + + private async Task> GetBlockTemplateAsync(CancellationToken ct) + { + var request = new GetBlockTemplateRequest + { + WalletAddress = poolConfig.Address, + ReserveSize = ConcealConstants.ReserveSize + }; + + return await rpc.ExecuteAsync(logger, ConcealCommands.GetBlockTemplate, ct, request); + } + + private RpcResponse GetBlockTemplateFromJson(string json) + { + var result = JsonConvert.DeserializeObject(json); + + return new RpcResponse(result.ResultAs()); + } + + private async Task ShowDaemonSyncProgressAsync(CancellationToken ct) + { + var info = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); + + if(info.Status != "OK") + { + var lowestHeight = info.Height; + + var totalBlocks = info.TargetHeight; + var percent = (double) lowestHeight / totalBlocks * 100; + + logger.Info(() => $"Daemon has downloaded {percent:0.00}% of blockchain from {info.OutgoingConnectionsCount} peers"); + } + } + + private async Task UpdateNetworkStatsAsync(CancellationToken ct) + { + try + { + var coin = poolConfig.Template.As(); + var info = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); + + if(info.Status != "OK") + logger.Warn(() => $"Error(s) refreshing network stats..."); + + if(info.Status == "OK") + { + BlockchainStats.NetworkHashrate = info.TargetHeight > 0 ? (double) info.Difficulty / coin.DifficultyTarget : 0; + BlockchainStats.ConnectedPeers = info.OutgoingConnectionsCount + info.IncomingConnectionsCount; + } + } + + catch(Exception e) + { + logger.Error(e); + } + } + + private async Task SubmitBlockAsync(Share share, string blobHex, string blobHash) + { + var response = await rpc.ExecuteAsync(logger, ConcealCommands.SubmitBlock, CancellationToken.None, new[] { blobHex }); + + if(response.Error != null || response?.Response?.Status != "OK") + { + var error = response.Error?.Message ?? response.Response?.Status; + + logger.Warn(() => $"Block {share.BlockHeight} [{blobHash[..6]}] submission failed with: {error}"); + messageBus.SendMessage(new AdminNotification("Block submission failed", $"Pool {poolConfig.Id} {(!string.IsNullOrEmpty(share.Source) ? $"[{share.Source.ToUpper()}] " : string.Empty)}failed to submit block {share.BlockHeight}: {error}")); + return false; + } + + return true; + } + + #region API-Surface + + public IObservable Blocks { get; private set; } + + public ConcealCoinTemplate Coin => coin; + + public override void Configure(PoolConfig pc, ClusterConfig cc) + { + Contract.RequiresNonNull(pc); + Contract.RequiresNonNull(cc); + + logger = LogUtil.GetPoolScopedLogger(typeof(JobManagerBase), pc); + poolConfig = pc; + clusterConfig = cc; + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + coin = pc.Template.As(); + + var NetworkTypeOverride = !string.IsNullOrEmpty(extraPoolConfig?.NetworkTypeOverride) ? extraPoolConfig.NetworkTypeOverride : "testnet"; + + switch(NetworkTypeOverride.ToLower()) + { + case "mainnet": + networkType = ConcealNetworkType.Main; + break; + case "testnet": + networkType = ConcealNetworkType.Test; + break; + default: + throw new PoolStartupException($"Unsupport net type '{NetworkTypeOverride}'", poolConfig.Id); + } + + // extract standard daemon endpoints + daemonEndpoints = pc.Daemons + .Where(x => string.IsNullOrEmpty(x.Category)) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = ConcealConstants.DaemonRpcLocation; + + return x; + }) + .ToArray(); + + if(cc.PaymentProcessing?.Enabled == true && pc.PaymentProcessing?.Enabled == true) + { + // extract wallet daemon endpoints + walletDaemonEndpoints = pc.Daemons + .Where(x => x.Category?.ToLower() == ConcealConstants.WalletDaemonCategory) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = ConcealConstants.DaemonRpcLocation; + + return x; + }) + .ToArray(); + + if(walletDaemonEndpoints.Length == 0) + throw new PoolStartupException("Wallet-RPC daemon is not configured (Daemon configuration for conceal-pools require an additional entry of category \'wallet' pointing to the wallet daemon)", pc.Id); + } + + ConfigureDaemons(); + } + + public bool ValidateAddress(string address) + { + if(string.IsNullOrEmpty(address)) + return false; + + var addressPrefix = CryptonoteBindings.DecodeAddress(address); + var addressIntegratedPrefix = CryptonoteBindings.DecodeIntegratedAddress(address); + var coin = poolConfig.Template.As(); + + switch(networkType) + { + case ConcealNetworkType.Main: + if(addressPrefix != coin.AddressPrefix) + return false; + break; + + case ConcealNetworkType.Test: + if(addressPrefix != coin.AddressPrefixTestnet) + return false; + break; + } + + return true; + } + + public BlockchainStats BlockchainStats { get; } = new(); + + public void PrepareWorkerJob(ConcealWorkerJob workerJob, out string blob, out string target) + { + blob = null; + target = null; + + var job = currentJob; + + if(job != null) + { + lock(job) + { + job.PrepareWorkerJob(workerJob, out blob, out target); + } + } + } + + public async ValueTask SubmitShareAsync(StratumConnection worker, + ConcealSubmitShareRequest request, ConcealWorkerJob workerJob, CancellationToken ct) + { + Contract.RequiresNonNull(worker); + Contract.RequiresNonNull(request); + + var context = worker.ContextAs(); + + var job = currentJob; + if(workerJob.Height != job?.BlockTemplate.Height) + throw new StratumException(StratumError.MinusOne, "block expired"); + + // validate & process + var (share, blobHex) = job.ProcessShare(request.Nonce, workerJob.ExtraNonce, request.Hash, worker); + + // enrich share with common data + share.PoolId = poolConfig.Id; + share.IpAddress = worker.RemoteEndpoint.Address.ToString(); + share.Miner = context.Miner; + share.Worker = context.Worker; + share.UserAgent = context.UserAgent; + share.Source = clusterConfig.ClusterName; + share.NetworkDifficulty = job.BlockTemplate.Difficulty; + share.Created = clock.Now; + + // if block candidate, submit & check if accepted by network + if(share.IsBlockCandidate) + { + logger.Info(() => $"Submitting block {share.BlockHeight} [{share.BlockHash[..6]}]"); + + share.IsBlockCandidate = await SubmitBlockAsync(share, blobHex, share.BlockHash); + + if(share.IsBlockCandidate) + { + logger.Info(() => $"Daemon accepted block {share.BlockHeight} [{share.BlockHash[..6]}] submitted by {context.Miner}"); + + OnBlockFound(); + + share.TransactionConfirmationData = share.BlockHash; + } + + else + { + // clear fields that no longer apply + share.TransactionConfirmationData = null; + } + } + + return share; + } + + #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); + } + + #region Overrides + + protected override void ConfigureDaemons() + { + var jsonSerializerSettings = ctx.Resolve(); + + restClient = new SimpleRestClient(httpClientFactory, "http://" + daemonEndpoints.First().Host.ToString() + ":" + daemonEndpoints.First().Port.ToString() + "/"); + rpc = new RpcClient(daemonEndpoints.First(), jsonSerializerSettings, messageBus, poolConfig.Id); + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + // also setup wallet daemon + walletRpc = new RpcClient(walletDaemonEndpoints.First(), jsonSerializerSettings, messageBus, poolConfig.Id); + } + } + + protected override async Task AreDaemonsHealthyAsync(CancellationToken ct) + { + logger.Debug(() => "Checking if conceald daemon is healthy..."); + + // test daemons + var response = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); + if(response.Status != "OK") + { + logger.Debug(() => $"conceald daemon did not responded..."); + return false; + } + + logger.Debug(() => $"{response.Status} - Incoming: {response.IncomingConnectionsCount} - Outgoing: {response.OutgoingConnectionsCount})"); + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + logger.Debug(() => "Checking if walletd daemon is healthy..."); + + // test wallet daemons + //var response2 = await walletRpc.ExecuteAsync(logger, ConcealWalletCommands.GetAddress, ct); + var request2 = new GetBalanceRequest + { + Address = poolConfig.Address + }; + + var response2 = await walletRpc.ExecuteAsync(logger, ConcealWalletCommands.GetBalance, ct, request2); + + if(response2.Error != null) + logger.Debug(() => $"walletd daemon response: {response2.Error.Message} (Code {response2.Error.Code})"); + + return response2.Error == null; + } + + return true; + } + + protected override async Task AreDaemonsConnectedAsync(CancellationToken ct) + { + logger.Debug(() => "Checking if conceald daemon is connected..."); + + var response = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); + + if(response.Status != "OK") + logger.Debug(() => $"conceald daemon is not connected..."); + + if(response.Status == "OK") + logger.Debug(() => $"Peers connected - Incoming: {response.IncomingConnectionsCount} - Outgoing: {response.OutgoingConnectionsCount}"); + + return response.Status == "OK" && + (response.OutgoingConnectionsCount + response.IncomingConnectionsCount) > 0; + } + + protected override async Task EnsureDaemonsSynchedAsync(CancellationToken ct) + { + using var timer = new PeriodicTimer(TimeSpan.FromSeconds(5)); + + logger.Debug(() => "Checking if conceald daemon is synched..."); + + var syncPendingNotificationShown = false; + + do + { + var request = new GetBlockTemplateRequest + { + WalletAddress = poolConfig.Address, + ReserveSize = ConcealConstants.ReserveSize + }; + + var response = await rpc.ExecuteAsync(logger, + ConcealCommands.GetBlockTemplate, ct, request); + + if(response.Error != null) + logger.Debug(() => $"conceald daemon response: {response.Error.Message} (Code {response.Error.Code})"); + + var isSynched = response.Error is not {Code: -9}; + + if(isSynched) + { + logger.Info(() => "All daemons synched with blockchain"); + break; + } + + if(!syncPendingNotificationShown) + { + logger.Info(() => "Daemon is still syncing with network. Manager will be started once synced."); + syncPendingNotificationShown = true; + } + + await ShowDaemonSyncProgressAsync(ct); + } while(await timer.WaitForNextTickAsync(ct)); + } + + protected override async Task PostStartInitAsync(CancellationToken ct) + { + SetInstanceId(); + + // coin config + var coin = poolConfig.Template.As(); + var infoResponse = await restClient.Get(ConcealConstants.DaemonRpcGetInfoLocation, ct); + + if(infoResponse.Status != "OK") + throw new PoolStartupException($"Init RPC failed...", poolConfig.Id); + + if(clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) + { + //var addressResponse = await walletRpc.ExecuteAsync(logger, ConcealWalletCommands.GetAddress, ct); + var request2 = new GetAddressRequest + { + }; + + var addressResponse = await walletRpc.ExecuteAsync(logger, ConcealWalletCommands.GetAddress, ct, request2); + + // ensure pool owns wallet + //if(clusterConfig.PaymentProcessing?.Enabled == true && addressResponse.Response?.Address != poolConfig.Address) + if(clusterConfig.PaymentProcessing?.Enabled == true && Exists(addressResponse.Response?.Address, element => element == poolConfig.Address) == false) + throw new PoolStartupException($"Wallet-Daemon does not own pool-address '{poolConfig.Address}'", poolConfig.Id); + } + + // address validation + poolAddressBase58Prefix = CryptonoteBindings.DecodeAddress(poolConfig.Address); + if(poolAddressBase58Prefix == 0) + throw new PoolStartupException("Unable to decode pool-address", poolConfig.Id); + + switch(networkType) + { + case ConcealNetworkType.Main: + if(poolAddressBase58Prefix != coin.AddressPrefix) + throw new PoolStartupException($"Invalid pool address prefix. Expected {coin.AddressPrefix}, got {poolAddressBase58Prefix}", poolConfig.Id); + break; + + case ConcealNetworkType.Test: + if(poolAddressBase58Prefix != coin.AddressPrefixTestnet) + throw new PoolStartupException($"Invalid pool address prefix. Expected {coin.AddressPrefixTestnet}, got {poolAddressBase58Prefix}", poolConfig.Id); + break; + } + + // update stats + BlockchainStats.RewardType = "POW"; + BlockchainStats.NetworkType = networkType.ToString(); + + await UpdateNetworkStatsAsync(ct); + + // Periodically update network stats + Observable.Interval(TimeSpan.FromMinutes(1)) + .Select(via => Observable.FromAsync(() => + Guard(()=> UpdateNetworkStatsAsync(ct), + ex=> logger.Error(ex)))) + .Concat() + .Subscribe(); + + SetupJobUpdates(ct); + } + + private void SetInstanceId() + { + instanceId = new byte[ConcealConstants.InstanceIdSize]; + + using(var rng = RandomNumberGenerator.Create()) + { + rng.GetNonZeroBytes(instanceId); + } + + if(clusterConfig.InstanceId.HasValue) + instanceId[0] = clusterConfig.InstanceId.Value; + } + + protected virtual void SetupJobUpdates(CancellationToken ct) + { + var blockSubmission = blockFoundSubject.Synchronize(); + var pollTimerRestart = blockFoundSubject.Synchronize(); + + var triggers = new List> + { + blockSubmission.Select(x => (JobRefreshBy.BlockFound, (string) null)) + }; + + if(extraPoolConfig?.BtStream == null) + { + // collect ports + var zmq = poolConfig.Daemons + .Where(x => !string.IsNullOrEmpty(x.Extra.SafeExtensionDataAs()?.ZmqBlockNotifySocket)) + .ToDictionary(x => x, x => + { + var extra = x.Extra.SafeExtensionDataAs(); + var topic = !string.IsNullOrEmpty(extra.ZmqBlockNotifyTopic.Trim()) ? extra.ZmqBlockNotifyTopic.Trim() : BitcoinConstants.ZmqPublisherTopicBlockHash; + + return (Socket: extra.ZmqBlockNotifySocket, Topic: topic); + }); + + if(zmq.Count > 0) + { + logger.Info(() => $"Subscribing to ZMQ push-updates from {string.Join(", ", zmq.Values)}"); + + var blockNotify = rpc.ZmqSubscribe(logger, ct, 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("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) + return msg[0].Read().ToHexString(); + } + }) + .DistinctUntilChanged() + .Select(_ => (JobRefreshBy.PubSub, (string) null)) + .Publish() + .RefCount(); + + pollTimerRestart = Observable.Merge( + blockSubmission, + blockNotify.Select(_ => Unit.Default)) + .Publish() + .RefCount(); + + triggers.Add(blockNotify); + } + + if(poolConfig.BlockRefreshInterval > 0) + { + // periodically update block-template + var pollingInterval = poolConfig.BlockRefreshInterval > 0 ? poolConfig.BlockRefreshInterval : 1000; + + triggers.Add(Observable.Timer(TimeSpan.FromMilliseconds(pollingInterval)) + .TakeUntil(pollTimerRestart) + .Select(_ => (JobRefreshBy.Poll, (string) null)) + .Repeat()); + } + + else + { + // get initial blocktemplate + triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) + .Select(_ => (JobRefreshBy.Initial, (string) null)) + .TakeWhile(_ => !hasInitialBlockTemplate)); + } + } + + else + { + triggers.Add(BtStreamSubscribe(extraPoolConfig.BtStream) + .Select(json => (JobRefreshBy.BlockTemplateStream, json)) + .Publish() + .RefCount()); + + // get initial blocktemplate + triggers.Add(Observable.Interval(TimeSpan.FromMilliseconds(1000)) + .Select(_ => (JobRefreshBy.Initial, (string) null)) + .TakeWhile(_ => !hasInitialBlockTemplate)); + } + + Blocks = triggers.Merge() + .Select(x => Observable.FromAsync(() => UpdateJob(ct, x.Via, x.Data))) + .Concat() + .Where(isNew => isNew) + .Do(_ => hasInitialBlockTemplate = true) + .Select(_ => Unit.Default) + .Publish() + .RefCount(); + } + + #endregion // Overrides +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/ConcealPayoutHandler.cs b/src/Miningcore/Blockchain/Conceal/ConcealPayoutHandler.cs new file mode 100644 index 000000000..22bc78164 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/ConcealPayoutHandler.cs @@ -0,0 +1,497 @@ +using System.Data; +using Autofac; +using AutoMapper; +using Miningcore.Blockchain.Conceal.Configuration; +using Miningcore.Blockchain.Conceal.DaemonRequests; +using Miningcore.Blockchain.Conceal.DaemonResponses; +using Miningcore.Configuration; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Native; +using Miningcore.Payments; +using Miningcore.Persistence; +using Miningcore.Persistence.Model; +using Miningcore.Persistence.Repositories; +using Miningcore.Rest; +using Miningcore.Rpc; +using Miningcore.Time; +using Miningcore.Util; +using Newtonsoft.Json; +using Contract = Miningcore.Contracts.Contract; +using CNC = Miningcore.Blockchain.Conceal.ConcealCommands; +using Newtonsoft.Json.Linq; + +namespace Miningcore.Blockchain.Conceal; + +[CoinFamily(CoinFamily.Conceal)] +public class ConcealPayoutHandler : PayoutHandlerBase, + IPayoutHandler +{ + public ConcealPayoutHandler( + IComponentContext ctx, + IConnectionFactory cf, + IMapper mapper, + IShareRepository shareRepo, + IBlockRepository blockRepo, + IBalanceRepository balanceRepo, + IPaymentRepository paymentRepo, + IMasterClock clock, + IHttpClientFactory httpClientFactory, + IMessageBus messageBus) : + base(cf, mapper, shareRepo, blockRepo, balanceRepo, paymentRepo, clock, messageBus) + { + Contract.RequiresNonNull(ctx); + Contract.RequiresNonNull(balanceRepo); + Contract.RequiresNonNull(paymentRepo); + + this.ctx = ctx; + this.httpClientFactory = httpClientFactory; + } + + private readonly IComponentContext ctx; + private IHttpClientFactory httpClientFactory; + private SimpleRestClient restClient; + private RpcClient rpcClient; + private RpcClient rpcClientWallet; + private ConcealNetworkType? networkType; + private ConcealPoolPaymentProcessingConfigExtra extraConfig; + private ConcealPoolConfigExtra extraPoolConfig; + private bool walletSupportsSendTransaction; + + protected override string LogCategory => "Conceal Payout Handler"; + + private async Task HandleSendTransactionResponseAsync(RpcResponse response, params Balance[] balances) + { + var coin = poolConfig.Template.As(); + + if(response.Error == null) + { + var txHash = response.Response.TxHash; + var txFee = ConcealConstants.StaticTransactionFeeReserve; + + logger.Info(() => $"[{LogCategory}] Payment transaction id: {txHash}, TxFee {FormatAmount(txFee)}"); + + await PersistPaymentsAsync(balances, txHash); + NotifyPayoutSuccess(poolConfig.Id, balances, new[] { txHash }, txFee); + return true; + } + + else + { + logger.Error(() => $"[{LogCategory}] Daemon command '{ConcealWalletCommands.SendTransaction}' returned error: {response.Error.Message} code {response.Error.Code}"); + + NotifyPayoutFailure(poolConfig.Id, balances, $"Daemon command '{ConcealWalletCommands.SendTransaction}' returned error: {response.Error.Message} code {response.Error.Code}", null); + return false; + } + } + + private async Task EnsureBalance(decimal requiredAmount, ConcealCoinTemplate coin, CancellationToken ct) + { + //var response = await rpcClientWallet.ExecuteAsync(logger, ConcealWalletCommands.GetBalance, ct); + var request = new GetBalanceRequest + { + Address = poolConfig.Address + }; + + var response = await rpcClientWallet.ExecuteAsync(logger, ConcealWalletCommands.GetBalance, ct, request); + + if(response.Error != null) + { + logger.Error(() => $"[{LogCategory}] Daemon command '{ConcealWalletCommands.GetBalance}' returned error: {response.Error.Message} code {response.Error.Code}"); + return false; + } + + var balance = Math.Floor(response.Response.Balance / coin.SmallestUnit); + + if(balance < requiredAmount) + { + logger.Info(() => $"[{LogCategory}] {FormatAmount(requiredAmount)} required for payment, but only have {FormatAmount(balance)} available yet. Will try again."); + return false; + } + + logger.Info(() => $"[{LogCategory}] Current balance is {FormatAmount(balance)}"); + return true; + } + + private async Task PayoutBatch(Balance[] balances, CancellationToken ct) + { + var coin = poolConfig.Template.As(); + + // ensure there's enough balance + if(!await EnsureBalance(balances.Sum(x => x.Amount), coin, ct)) + return false; + + // build request + var request = new SendTransactionRequest + { + Addresses = new string[] + { + poolConfig.Address + }, + Transfers = balances + .Where(x => x.Amount > 0) + .Select(x => + { + ExtractAddressAndPaymentId(x.Address, out var address, out _); + + logger.Debug(() => $"[{LogCategory}] [batch] ['address': '{x.Address} - {address}', 'amount': {Math.Floor(x.Amount * coin.SmallestUnit)}]"); + + return new SendTransactionTransfers + { + Address = address, + Amount = (ulong) Math.Floor(x.Amount * coin.SmallestUnit) + }; + }).ToArray(), + ChangeAddress = poolConfig.Address + }; + + if(request.Transfers.Length == 0) + return true; + + logger.Debug(() => $"[{LogCategory}] [batch] RPC data: ['anonymity': {request.Anonymity}, 'fee': {request.Fee}, 'unlockTime': {request.UnlockTime}, 'changeAddress': '{request.ChangeAddress}']"); + logger.Info(() => $"[{LogCategory}] [batch] Paying {FormatAmount(balances.Sum(x => x.Amount))} to {balances.Length} addresses:\n{string.Join("\n", balances.OrderByDescending(x => x.Amount).Select(x => $"{FormatAmount(x.Amount)} to {x.Address}"))}"); + + // send command + var sendTransactionResponse = await rpcClientWallet.ExecuteAsync(logger, ConcealWalletCommands.SendTransaction, ct, request); + + return await HandleSendTransactionResponseAsync(sendTransactionResponse, balances); + } + + private void ExtractAddressAndPaymentId(string input, out string address, out string paymentId) + { + paymentId = null; + var index = input.IndexOf(PayoutConstants.PayoutInfoSeperator); + + if(index != -1) + { + address = input[..index]; + + if(index + 1 < input.Length) + { + paymentId = input[(index + 1)..]; + + // ignore invalid payment ids + if(paymentId.Length != ConcealConstants.PaymentIdHexLength) + paymentId = null; + } + } + + else + address = input; + } + + private async Task PayoutToPaymentId(Balance balance, CancellationToken ct) + { + var coin = poolConfig.Template.As(); + + ExtractAddressAndPaymentId(balance.Address, out var address, out var paymentId); + var isIntegratedAddress = string.IsNullOrEmpty(paymentId); + + // ensure there's enough balance + if(!await EnsureBalance(balance.Amount, coin, ct)) + return false; + + // build request + var request = new SendTransactionRequest + { + Addresses = new string[] + { + poolConfig.Address + }, + Transfers = new[] + { + new SendTransactionTransfers + { + Address = address, + Amount = (ulong) Math.Floor(balance.Amount * coin.SmallestUnit) + } + }, + ChangeAddress = poolConfig.Address + }; + + if(!isIntegratedAddress) + logger.Info(() => $"[{LogCategory}] Paying {FormatAmount(balance.Amount)} to address {balance.Address} with paymentId {paymentId}"); + else + logger.Info(() => $"[{LogCategory}] Paying {FormatAmount(balance.Amount)} to integrated address {balance.Address}"); + + // send command + var result = await rpcClientWallet.ExecuteAsync(logger, ConcealWalletCommands.SendTransaction, ct, request); + + return await HandleSendTransactionResponseAsync(result, balance); + } + + #region IPayoutHandler + + public async Task ConfigureAsync(ClusterConfig cc, PoolConfig pc, CancellationToken ct) + { + Contract.RequiresNonNull(pc); + + poolConfig = pc; + clusterConfig = cc; + extraConfig = pc.PaymentProcessing.Extra.SafeExtensionDataAs(); + extraPoolConfig = pc.Extra.SafeExtensionDataAs(); + + var NetworkTypeOverride = !string.IsNullOrEmpty(extraPoolConfig.NetworkTypeOverride) ? extraPoolConfig.NetworkTypeOverride : "testnet"; + + switch(NetworkTypeOverride.ToLower()) + { + case "mainnet": + networkType = ConcealNetworkType.Main; + break; + case "testnet": + networkType = ConcealNetworkType.Test; + break; + default: + throw new PoolStartupException($"Unsupport net type '{NetworkTypeOverride}'", poolConfig.Id); + } + + logger = LogUtil.GetPoolScopedLogger(typeof(ConcealPayoutHandler), pc); + + // configure standard daemon + var jsonSerializerSettings = ctx.Resolve(); + + var daemonEndpoints = pc.Daemons + .Where(x => string.IsNullOrEmpty(x.Category)) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = ConcealConstants.DaemonRpcLocation; + + return x; + }) + .ToArray(); + + restClient = new SimpleRestClient(httpClientFactory, "http://" + daemonEndpoints.First().Host.ToString() + ":" + daemonEndpoints.First().Port.ToString() + "/"); + rpcClient = new RpcClient(daemonEndpoints.First(), jsonSerializerSettings, messageBus, pc.Id); + + // configure wallet daemon + var walletDaemonEndpoints = pc.Daemons + .Where(x => x.Category?.ToLower() == ConcealConstants.WalletDaemonCategory) + .Select(x => + { + if(string.IsNullOrEmpty(x.HttpPath)) + x.HttpPath = ConcealConstants.DaemonRpcLocation; + + return x; + }) + .ToArray(); + + rpcClientWallet = new RpcClient(walletDaemonEndpoints.First(), jsonSerializerSettings, messageBus, pc.Id); + + // detect sendTransaction support + var response = await rpcClientWallet.ExecuteAsync(logger, ConcealWalletCommands.SendTransaction, ct); + walletSupportsSendTransaction = response.Error.Code != ConcealConstants.ConcealRpcMethodNotFound; + } + + public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, CancellationToken ct) + { + Contract.RequiresNonNull(poolConfig); + Contract.RequiresNonNull(blocks); + + var coin = poolConfig.Template.As(); + var pageSize = 100; + var pageCount = (int) Math.Ceiling(blocks.Length / (double) pageSize); + var result = new List(); + + for(var i = 0; i < pageCount; i++) + { + // get a page full of blocks + var page = blocks + .Skip(i * pageSize) + .Take(pageSize) + .ToArray(); + + // NOTE: conceald does not support batch-requests??? + for(var j = 0; j < page.Length; j++) + { + var block = page[j]; + + var rpcResult = await rpcClient.ExecuteAsync(logger, + CNC.GetBlockHeaderByHeight, ct, + new GetBlockHeaderByHeightRequest + { + Height = block.BlockHeight + }); + + if(rpcResult.Error != null) + { + logger.Debug(() => $"[{LogCategory}] Daemon reports error '{rpcResult.Error.Message}' (Code {rpcResult.Error.Code}) for block {block.BlockHeight}"); + continue; + } + + if(rpcResult.Response?.BlockHeader == null) + { + logger.Debug(() => $"[{LogCategory}] Daemon returned no header for block {block.BlockHeight}"); + continue; + } + + var blockHeader = rpcResult.Response.BlockHeader; + + // update progress + block.ConfirmationProgress = Math.Min(1.0d, (double) blockHeader.Depth / ConcealConstants.PayoutMinBlockConfirmations); + result.Add(block); + + messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); + + // orphaned? + if(blockHeader.IsOrphaned || blockHeader.Hash != block.TransactionConfirmationData) + { + block.Status = BlockStatus.Orphaned; + block.Reward = 0; + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + continue; + } + + // matured and spendable? + if(blockHeader.Depth >= ConcealConstants.PayoutMinBlockConfirmations) + { + block.Status = BlockStatus.Confirmed; + block.ConfirmationProgress = 1; + block.Reward = (blockHeader.Reward / coin.SmallestUnit) * coin.BlockrewardMultiplier; + + logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } + } + } + + return result.ToArray(); + } + + public override async Task UpdateBlockRewardBalancesAsync(IDbConnection con, IDbTransaction tx, + IMiningPool pool, Block block, CancellationToken ct) + { + var blockRewardRemaining = await base.UpdateBlockRewardBalancesAsync(con, tx, pool, block, ct); + + // Deduct static reserve for tx fees + blockRewardRemaining -= ConcealConstants.StaticTransactionFeeReserve; + + return blockRewardRemaining; + } + + public async Task PayoutAsync(IMiningPool pool, Balance[] balances, CancellationToken ct) + { + Contract.RequiresNonNull(balances); + + var coin = poolConfig.Template.As(); + +#if !DEBUG // ensure we have peers + var infoResponse = await restClient.Get(CNC.GetInfo, ct); + + if (infoResponse.Status != "OK" || + infoResponse.IncomingConnectionsCount + infoResponse.OutgoingConnectionsCount < 3) + { + logger.Warn(() => $"[{LogCategory}] Payout aborted. Not enough peers (4 required)"); + return; + } +#endif + // validate addresses + balances = balances + .Where(x => + { + ExtractAddressAndPaymentId(x.Address, out var address, out _); + + var addressPrefix = CryptonoteBindings.DecodeAddress(address); + var addressIntegratedPrefix = CryptonoteBindings.DecodeIntegratedAddress(address); + + switch(networkType) + { + case ConcealNetworkType.Main: + if(addressPrefix != coin.AddressPrefix) + { + logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address: {x.Address}"); + return false; + } + + break; + + case ConcealNetworkType.Test: + if(addressPrefix != coin.AddressPrefixTestnet) + { + logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address: {x.Address}"); + return false; + } + + break; + } + + return true; + }) + .ToArray(); + + // simple balances first + var simpleBalances = balances + .Where(x => + { + ExtractAddressAndPaymentId(x.Address, out var address, out var paymentId); + + var hasPaymentId = paymentId != null; + var isIntegratedAddress = false; + var addressIntegratedPrefix = CryptonoteBindings.DecodeIntegratedAddress(address); + + switch(networkType) + { + case ConcealNetworkType.Main: + if(addressIntegratedPrefix == coin.AddressPrefixIntegrated) + isIntegratedAddress = true; + break; + + case ConcealNetworkType.Test: + if(addressIntegratedPrefix == coin.AddressPrefixIntegratedTestnet) + isIntegratedAddress = true; + break; + } + + return !hasPaymentId && !isIntegratedAddress; + }) + .OrderByDescending(x => x.Amount) + .ToArray(); + + if(simpleBalances.Length > 0) +#if false + await PayoutBatch(simpleBalances); +#else + { + var maxBatchSize = 15; // going over 15 yields "sv/gamma are too large" + var pageSize = maxBatchSize; + var pageCount = (int) Math.Ceiling((double) simpleBalances.Length / pageSize); + + for(var i = 0; i < pageCount; i++) + { + var page = simpleBalances + .Skip(i * pageSize) + .Take(pageSize) + .ToArray(); + + if(!await PayoutBatch(page, ct)) + break; + } + } +#endif + // balances with paymentIds + var minimumPaymentToPaymentId = extraConfig?.MinimumPaymentToPaymentId ?? poolConfig.PaymentProcessing.MinimumPayment; + + var paymentIdBalances = balances.Except(simpleBalances) + .Where(x => x.Amount >= minimumPaymentToPaymentId) + .ToArray(); + + foreach(var balance in paymentIdBalances) + { + if(!await PayoutToPaymentId(balance, ct)) + break; + } + + // save wallet + await rpcClientWallet.ExecuteAsync(logger, ConcealWalletCommands.Save, ct); + } + + public double AdjustBlockEffort(double effort) + { + return effort; + } + + #endregion // IPayoutHandler +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/ConcealPool.cs b/src/Miningcore/Blockchain/Conceal/ConcealPool.cs new file mode 100644 index 000000000..99806e998 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/ConcealPool.cs @@ -0,0 +1,423 @@ +using System.Globalization; +using System.Reactive; +using System.Reactive.Linq; +using System.Reactive.Threading.Tasks; +using Autofac; +using AutoMapper; +using Microsoft.IO; +using Miningcore.Blockchain.Conceal.StratumRequests; +using Miningcore.Blockchain.Conceal.StratumResponses; +using Miningcore.Configuration; +using Miningcore.JsonRpc; +using Miningcore.Messaging; +using Miningcore.Mining; +using Miningcore.Nicehash; +using Miningcore.Notifications.Messages; +using Miningcore.Payments; +using Miningcore.Persistence; +using Miningcore.Persistence.Repositories; +using Miningcore.Stratum; +using Miningcore.Time; +using Newtonsoft.Json; +using static Miningcore.Util.ActionUtils; + +namespace Miningcore.Blockchain.Conceal; + +[CoinFamily(CoinFamily.Conceal)] +public class ConcealPool : PoolBase +{ + public ConcealPool(IComponentContext ctx, + JsonSerializerSettings serializerSettings, + IConnectionFactory cf, + IStatsRepository statsRepo, + IMapper mapper, + IMasterClock clock, + IMessageBus messageBus, + RecyclableMemoryStreamManager rmsm, + NicehashService nicehashService) : + base(ctx, serializerSettings, cf, statsRepo, mapper, clock, messageBus, rmsm, nicehashService) + { + } + + private long currentJobId; + + private ConcealJobManager manager; + private string minerAlgo; + + private async Task OnLoginAsync(StratumConnection connection, Timestamped tsRequest) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + var loginRequest = request.ParamsAs(); + + if(string.IsNullOrEmpty(loginRequest?.Login)) + throw new StratumException(StratumError.MinusOne, "missing login"); + + // extract worker/miner/paymentid + var split = loginRequest.Login.Split('.'); + context.Miner = split[0].Trim(); + context.Worker = split.Length > 1 ? split[1].Trim() : null; + context.UserAgent = loginRequest.UserAgent?.Trim(); + + var addressToValidate = context.Miner; + + // extract paymentid + var index = context.Miner.IndexOf('#'); + if(index != -1) + { + var paymentId = context.Miner[(index + 1)..].Trim(); + + // validate + if(!string.IsNullOrEmpty(paymentId) && paymentId.Length != ConcealConstants.PaymentIdHexLength) + throw new StratumException(StratumError.MinusOne, "invalid payment id"); + + // re-append to address + addressToValidate = context.Miner[..index].Trim(); + context.Miner = addressToValidate + PayoutConstants.PayoutInfoSeperator + paymentId; + } + + // validate login + var result = manager.ValidateAddress(addressToValidate); + + context.IsSubscribed = result; + context.IsAuthorized = result; + + if(context.IsAuthorized) + { + // extract control vars from password + var passParts = loginRequest.Password?.Split(PasswordControlVarsSeparator); + var staticDiff = GetStaticDiffFromPassparts(passParts); + + // Nicehash support + var nicehashDiff = await GetNicehashStaticMinDiff(context, manager.Coin.Name, manager.Coin.GetAlgorithmName()); + + if(nicehashDiff.HasValue) + { + if(!staticDiff.HasValue || nicehashDiff > staticDiff) + { + logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using API supplied difficulty of {nicehashDiff.Value}"); + + staticDiff = nicehashDiff; + } + + else + logger.Info(() => $"[{connection.ConnectionId}] Nicehash detected. Using miner supplied difficulty of {staticDiff.Value}"); + } + + // Static diff + if(staticDiff.HasValue && + (context.VarDiff != null && staticDiff.Value >= context.VarDiff.Config.MinDiff || + context.VarDiff == null && staticDiff.Value > context.Difficulty)) + { + context.VarDiff = null; // disable vardiff + context.SetDifficulty(staticDiff.Value); + + logger.Info(() => $"[{connection.ConnectionId}] Static difficulty set to {staticDiff.Value}"); + } + + // respond + var loginResponse = new ConcealLoginResponse + { + Id = connection.ConnectionId, + Job = CreateWorkerJob(connection) + }; + + await connection.RespondAsync(loginResponse, request.Id); + + // log association + if(!string.IsNullOrEmpty(context.Worker)) + logger.Info(() => $"[{connection.ConnectionId}] Authorized worker {context.Worker}@{context.Miner}"); + else + logger.Info(() => $"[{connection.ConnectionId}] Authorized miner {context.Miner}"); + } + + else + { + await connection.RespondErrorAsync(StratumError.MinusOne, "invalid login", request.Id); + + if(clusterConfig?.Banning?.BanOnLoginFailure is null or true) + { + logger.Info(() => $"[{connection.ConnectionId}] Banning unauthorized worker {context.Miner} for {loginFailureBanTimeout.TotalSeconds} sec"); + + banManager.Ban(connection.RemoteEndpoint.Address, loginFailureBanTimeout); + + Disconnect(connection); + } + } + } + + private async Task OnGetJobAsync(StratumConnection connection, Timestamped tsRequest) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + var getJobRequest = request.ParamsAs(); + + // validate worker + if(connection.ConnectionId != getJobRequest?.WorkerId || !context.IsAuthorized) + throw new StratumException(StratumError.MinusOne, "unauthorized"); + + // respond + var job = CreateWorkerJob(connection); + await connection.RespondAsync(job, request.Id); + } + + private ConcealJobParams CreateWorkerJob(StratumConnection connection) + { + var context = connection.ContextAs(); + var job = new ConcealWorkerJob(NextJobId(), context.Difficulty); + + manager.PrepareWorkerJob(job, out var blob, out var target); + + // should never happen + if(string.IsNullOrEmpty(blob) || string.IsNullOrEmpty(blob)) + return null; + + var result = new ConcealJobParams + { + JobId = job.Id, + Blob = blob, + Target = target, + Height = job.Height + }; + + if(!string.IsNullOrEmpty(minerAlgo)) + result.Algorithm = minerAlgo; + + // update context + lock(context) + { + context.AddJob(job); + } + + return result; + } + + private async Task OnSubmitAsync(StratumConnection connection, Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + try + { + if(request.Id == null) + throw new StratumException(StratumError.MinusOne, "missing request id"); + + // check age of submission (aged submissions are usually caused by high server load) + var requestAge = clock.Now - tsRequest.Timestamp.UtcDateTime; + + if(requestAge > maxShareAge) + { + logger.Warn(() => $"[{connection.ConnectionId}] Dropping stale share submission request (server overloaded?)"); + return; + } + + // check request + var submitRequest = request.ParamsAs(); + + // validate worker + if(connection.ConnectionId != submitRequest?.WorkerId || !context.IsAuthorized) + throw new StratumException(StratumError.MinusOne, "unauthorized"); + + // recognize activity + context.LastActivity = clock.Now; + + ConcealWorkerJob job; + + lock(context) + { + var jobId = submitRequest?.JobId; + + if((job = context.FindJob(jobId)) == null) + throw new StratumException(StratumError.MinusOne, "invalid jobid"); + } + + // dupe check + if(!job.Submissions.TryAdd(submitRequest.Nonce, true)) + throw new StratumException(StratumError.MinusOne, "duplicate share"); + + // submit + var share = await manager.SubmitShareAsync(connection, submitRequest, job, ct); + await connection.RespondAsync(new ConcealResponseBase(), request.Id); + + // publish + messageBus.SendMessage(share); + + // telemetry + PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, true); + + logger.Info(() => $"[{connection.ConnectionId}] Share accepted: D={Math.Round(share.Difficulty, 3)}"); + + // update pool stats + if(share.IsBlockCandidate) + poolStats.LastPoolBlockTime = clock.Now; + + // update client stats + context.Stats.ValidShares++; + + await UpdateVarDiffAsync(connection, false, ct); + } + + catch(StratumException ex) + { + // telemetry + PublishTelemetry(TelemetryCategory.Share, clock.Now - tsRequest.Timestamp.UtcDateTime, false); + + // update client stats + context.Stats.InvalidShares++; + logger.Info(() => $"[{connection.ConnectionId}] Share rejected: {ex.Message} [{context.UserAgent}]"); + + // banning + ConsiderBan(connection, context, poolConfig.Banning); + + throw; + } + } + + private string NextJobId() + { + return Interlocked.Increment(ref currentJobId).ToString(CultureInfo.InvariantCulture); + } + + private async Task OnNewJobAsync() + { + logger.Info(() => "Broadcasting jobs"); + + await Guard(() => ForEachMinerAsync(async (connection, ct) => + { + // send job + var job = CreateWorkerJob(connection); + await connection.NotifyAsync(ConcealStratumMethods.JobNotify, job); + })); + } + + #region Overrides + + protected override async Task SetupJobManager(CancellationToken ct) + { + manager = ctx.Resolve(); + manager.Configure(poolConfig, clusterConfig); + + await manager.StartAsync(ct); + + if(poolConfig.EnableInternalStratum == true) + { + minerAlgo = GetMinerAlgo(); + + disposables.Add(manager.Blocks + .Select(_ => Observable.FromAsync(() => + Guard(OnNewJobAsync, + ex=> logger.Debug(() => $"{nameof(OnNewJobAsync)}: {ex.Message}")))) + .Concat() + .Subscribe(_ => { }, ex => + { + logger.Debug(ex, nameof(OnNewJobAsync)); + })); + + // start with initial blocktemplate + await manager.Blocks.Take(1).ToTask(ct); + } + + else + { + // keep updating NetworkStats + disposables.Add(manager.Blocks.Subscribe()); + } + } + + private string GetMinerAlgo() + { + switch(manager.Coin.Hash) + { + case CryptonightHashType.CryptonightCCX: + return $"cn-ccx"; + + case CryptonightHashType.CryptonightGPU: + return $"cn-gpu"; + } + + return null; + } + + protected override async Task InitStatsAsync(CancellationToken ct) + { + await base.InitStatsAsync(ct); + + blockchainStats = manager.BlockchainStats; + } + + protected override WorkerContextBase CreateWorkerContext() + { + return new ConcealWorkerContext(); + } + + protected override async Task OnRequestAsync(StratumConnection connection, + Timestamped tsRequest, CancellationToken ct) + { + var request = tsRequest.Value; + var context = connection.ContextAs(); + + try + { + switch(request.Method) + { + case ConcealStratumMethods.Login: + await OnLoginAsync(connection, tsRequest); + break; + + case ConcealStratumMethods.GetJob: + await OnGetJobAsync(connection, tsRequest); + break; + + case ConcealStratumMethods.Submit: + await OnSubmitAsync(connection, tsRequest, ct); + break; + + case ConcealStratumMethods.KeepAlive: + // recognize activity + context.LastActivity = clock.Now; + break; + + default: + logger.Debug(() => $"[{connection.ConnectionId}] Unsupported RPC request: {JsonConvert.SerializeObject(request, serializerSettings)}"); + + await connection.RespondErrorAsync(StratumError.Other, $"Unsupported request {request.Method}", request.Id); + break; + } + } + + catch(StratumException ex) + { + await connection.RespondErrorAsync(ex.Code, ex.Message, request.Id, false); + } + } + + public override double HashrateFromShares(double shares, double interval) + { + var result = shares / interval; + return result; + } + + public override double ShareMultiplier => 1; + + protected override async Task OnVarDiffUpdateAsync(StratumConnection connection, double newDiff, CancellationToken ct) + { + await base.OnVarDiffUpdateAsync(connection, newDiff, ct); + + if(connection.Context.ApplyPendingDifficulty()) + { + // re-send job + var job = CreateWorkerJob(connection); + await connection.NotifyAsync(ConcealStratumMethods.JobNotify, job); + } + } + + #endregion // Overrides +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/ConcealStratumMethods.cs b/src/Miningcore/Blockchain/Conceal/ConcealStratumMethods.cs new file mode 100644 index 000000000..c28111c0a --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/ConcealStratumMethods.cs @@ -0,0 +1,29 @@ +namespace Miningcore.Blockchain.Conceal; + +public class ConcealStratumMethods +{ + /// + /// Used to subscribe to work + /// + public const string Login = "login"; + + /// + /// New job notification + /// + public const string JobNotify = "job"; + + /// + /// Get Job request + /// + public const string GetJob = "getjob"; + + /// + /// Submit share request + /// + public const string Submit = "submit"; + + /// + /// Keep alive request + /// + public const string KeepAlive = "keepalived"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/ConcealWorkerContext.cs b/src/Miningcore/Blockchain/Conceal/ConcealWorkerContext.cs new file mode 100644 index 000000000..9539d0bfd --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/ConcealWorkerContext.cs @@ -0,0 +1,32 @@ +using Miningcore.Mining; + +namespace Miningcore.Blockchain.Conceal; + +public class ConcealWorkerContext : WorkerContextBase +{ + /// + /// Usually a wallet address + /// NOTE: May include paymentid (seperated by a dot .) + /// + public string Miner { get; set; } + + /// + /// Arbitrary worker identififer for miners using multiple rigs + /// + public string Worker { get; set; } + + private List validJobs { get; } = new(); + + public void AddJob(ConcealWorkerJob job) + { + validJobs.Insert(0, job); + + while(validJobs.Count > 4) + validJobs.RemoveAt(validJobs.Count - 1); + } + + public ConcealWorkerJob FindJob(string jobId) + { + return validJobs.FirstOrDefault(x => x.Id == jobId); + } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/ConcealWorkerJob.cs b/src/Miningcore/Blockchain/Conceal/ConcealWorkerJob.cs new file mode 100644 index 000000000..4bbc82d83 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/ConcealWorkerJob.cs @@ -0,0 +1,19 @@ +using System.Collections.Concurrent; + +namespace Miningcore.Blockchain.Conceal; + +public class ConcealWorkerJob +{ + public ConcealWorkerJob(string jobId, double difficulty) + { + Id = jobId; + Difficulty = difficulty; + } + + public string Id { get; } + public uint Height { get; set; } + public uint ExtraNonce { get; set; } + public double Difficulty { get; set; } + + public readonly ConcurrentDictionary Submissions = new(StringComparer.OrdinalIgnoreCase); +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/Configuration/ConcealDaemonEndpointConfigExtra.cs b/src/Miningcore/Blockchain/Conceal/Configuration/ConcealDaemonEndpointConfigExtra.cs new file mode 100644 index 000000000..721d37430 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/Configuration/ConcealDaemonEndpointConfigExtra.cs @@ -0,0 +1,16 @@ +namespace Miningcore.Blockchain.Conceal.Configuration; + +public class ConcealDaemonEndpointConfigExtra +{ + /// + /// Address of ZeroMQ block notify socket + /// Should match the value of -zmqpubhashblock daemon start parameter + /// + public string ZmqBlockNotifySocket { get; set; } + + /// + /// Optional: ZeroMQ block notify topic + /// Defaults to "hashblock" if left blank + /// + public string ZmqBlockNotifyTopic { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/Configuration/ConcealPoolConfigExtra.cs b/src/Miningcore/Blockchain/Conceal/Configuration/ConcealPoolConfigExtra.cs new file mode 100644 index 000000000..94598dfed --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/Configuration/ConcealPoolConfigExtra.cs @@ -0,0 +1,18 @@ +using Miningcore.Configuration; +using Newtonsoft.Json.Linq; + +namespace Miningcore.Blockchain.Conceal.Configuration; + +public class ConcealPoolConfigExtra +{ + /// + /// Blocktemplate stream published via ZMQ + /// + public ZmqPubSubEndpointConfig BtStream { get; set; } + + /// + /// Conceal does not have a RPC method which returns on which network it is operating, so user can specify which one + /// Defaults to `testnet` if not specified + /// + public string NetworkTypeOverride { get; set; } = null; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/Configuration/ConcealPoolPaymentProcessingConfigExtra.cs b/src/Miningcore/Blockchain/Conceal/Configuration/ConcealPoolPaymentProcessingConfigExtra.cs new file mode 100644 index 000000000..c77d581f3 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/Configuration/ConcealPoolPaymentProcessingConfigExtra.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Conceal.Configuration; + +public class ConcealPoolPaymentProcessingConfigExtra +{ + public decimal MinimumPaymentToPaymentId { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetAddressRequest.cs b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetAddressRequest.cs new file mode 100644 index 000000000..b8ae737e4 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetAddressRequest.cs @@ -0,0 +1,5 @@ +namespace Miningcore.Blockchain.Conceal.DaemonRequests; + +public class GetAddressRequest +{ +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetBalanceRequest.cs b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetBalanceRequest.cs new file mode 100644 index 000000000..f07412232 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetBalanceRequest.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.DaemonRequests; + +public class GetBalanceRequest +{ + /// + /// (Optional) If address is not specified, returns the balance of the first address in the wallet. + /// + [JsonProperty("address")] + public string Address { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetBlockHeaderByHashRequest.cs b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetBlockHeaderByHashRequest.cs new file mode 100644 index 000000000..1428dd321 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetBlockHeaderByHashRequest.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Conceal.DaemonRequests; + +public class GetBlockHeaderByHashRequest +{ + public string Hash { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetBlockHeaderByHeightRequest.cs b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetBlockHeaderByHeightRequest.cs new file mode 100644 index 000000000..3682b35c1 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetBlockHeaderByHeightRequest.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Conceal.DaemonRequests; + +public class GetBlockHeaderByHeightRequest +{ + public ulong Height { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetBlockTemplateRequest.cs b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetBlockTemplateRequest.cs new file mode 100644 index 000000000..9d24424cc --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetBlockTemplateRequest.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.DaemonRequests; + +public class GetBlockTemplateRequest +{ + /// + /// Address of wallet to receive coinbase transactions if block is successfully mined. + /// + [JsonProperty("wallet_address")] + public string WalletAddress { get; set; } + + [JsonProperty("reserve_size")] + public uint ReserveSize { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetInfoRequest.cs b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetInfoRequest.cs new file mode 100644 index 000000000..5075dc3bb --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetInfoRequest.cs @@ -0,0 +1,5 @@ +namespace Miningcore.Blockchain.Conceal.DaemonRequests; + +public class GetInfoRequest +{ +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetLastBlockHeaderRequest.cs b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetLastBlockHeaderRequest.cs new file mode 100644 index 000000000..6a4715387 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonRequests/GetLastBlockHeaderRequest.cs @@ -0,0 +1,5 @@ +namespace Miningcore.Blockchain.Conceal.DaemonRequests; + +public class GetLastBlockHeaderRequest +{ +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonRequests/SendTransactionRequest.cs b/src/Miningcore/Blockchain/Conceal/DaemonRequests/SendTransactionRequest.cs new file mode 100644 index 000000000..9a783eeb1 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonRequests/SendTransactionRequest.cs @@ -0,0 +1,55 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.DaemonRequests; + +public class SendTransactionTransfers +{ + [JsonProperty("address")] + public string Address { get; set; } + + [JsonProperty("amount")] + public ulong Amount { get; set; } +} + +public class SendTransactionRequest +{ + /// + /// Privacy level (a discrete number from 1 to infinity). Level 5 is recommended + /// + [JsonProperty("anonymity")] + public uint Anonymity { get; set; } = 5; + + /// + /// Transaction fee. The fee in Conceal is fixed at .001 CCX. This parameter should be specified in minimal available CCX units. For example, if your fee is .001 CCX, you should pass it as 1000 + /// + [JsonProperty("fee")] + public ulong Fee { get; set; } = 1000; + + /// + /// (Optional) Height of the block until which transaction is going to be locked for spending (0 to not add a lock) + /// + [JsonProperty("unlockTime")] + public uint UnlockTime { get; set; } = 0; + + /// + /// (Optional) Array of strings, where each string is an address to take the funds from + /// + [JsonProperty("addresses")] + public string[] Addresses { get; set; } + + /// + /// Array of strings and integers, where each string and integer are respectively an address and an amount where the funds are going to + /// + [JsonProperty("transfers")] + public SendTransactionTransfers[] Transfers { get; set; } + + /// + /// (Optional) Valid and existing address in the conceal wallet container used by walletd (Conceal Wallet RPC), it will receive the change of the transaction + /// IMPORTANT RULES: + /// 1: if container contains only 1 address, changeAddress field can be left empty and the change is going to be sent to this address + /// 2: if addresses field contains only 1 address, changeAddress can be left empty and the change is going to be sent to this address + /// 3: in the rest of the cases, changeAddress field is mandatory and must contain an address. + /// + [JsonProperty("changeAddress")] + public string ChangeAddress { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonRequests/SplitIntegratedAddressRequest.cs b/src/Miningcore/Blockchain/Conceal/DaemonRequests/SplitIntegratedAddressRequest.cs new file mode 100644 index 000000000..1a9fa7c7d --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonRequests/SplitIntegratedAddressRequest.cs @@ -0,0 +1,9 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.DaemonRequests; + +public class SplitIntegratedAddressRequest +{ + [JsonProperty("integrated_address")] + public string WalletAddress { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetAddressResponse.cs b/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetAddressResponse.cs new file mode 100644 index 000000000..7f5725d46 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetAddressResponse.cs @@ -0,0 +1,9 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.DaemonResponses; + +public class GetAddressResponse +{ + [JsonProperty("addresses")] + public string[] Address { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetBalanceResponse.cs b/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetBalanceResponse.cs new file mode 100644 index 000000000..af088cf09 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetBalanceResponse.cs @@ -0,0 +1,30 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.DaemonResponses; + +public class GetBalanceResponse +{ + /// + /// Available balance of the specified address + /// + [JsonProperty("availableBalance")] + public decimal Balance { get; set; } + + /// + /// Locked amount of the specified address + /// + [JsonProperty("lockedAmount")] + public decimal LockedBalance { get; set; } + + /// + /// Locked amount of the specified address + /// + [JsonProperty("lockedDepositBalance")] + public decimal LockedDepositBalance { get; set; } + + /// + /// Balance of unlocked deposits that can be withdrawn + /// + [JsonProperty("unlockedDepositBalance")] + public decimal UnlockedDepositBalance { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetBlockHeaderResponse.cs b/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetBlockHeaderResponse.cs new file mode 100644 index 000000000..502e1becd --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetBlockHeaderResponse.cs @@ -0,0 +1,35 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.DaemonResponses; + +public class BlockHeader +{ + public ulong Deposits { get; set; } + public long Difficulty { get; set; } + public long Depth { get; set; } + public uint Height { get; set; } + public string Hash { get; set; } + public string Nonce { get; set; } + public ulong Reward { get; set; } + public ulong Timestamp { get; set; } + + [JsonProperty("major_version")] + public uint MajorVersion { get; set; } + + [JsonProperty("minor_version")] + public uint MinorVersion { get; set; } + + [JsonProperty("prev_hash")] + public string PreviousBlockhash { get; set; } + + [JsonProperty("orphan_status")] + public bool IsOrphaned { get; set; } +} + +public class GetBlockHeaderResponse +{ + [JsonProperty("block_header")] + public BlockHeader BlockHeader { get; set; } + + public string Status { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetBlockTemplateResponse.cs b/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetBlockTemplateResponse.cs new file mode 100644 index 000000000..d54318749 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetBlockTemplateResponse.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.DaemonResponses; + +public class GetBlockTemplateResponse +{ + [JsonProperty("blocktemplate_blob")] + public string Blob { get; set; } + + public long Difficulty { get; set; } + public uint Height { get; set; } + + [JsonProperty("reserved_offset")] + public int ReservedOffset { get; set; } + + public string Status { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetInfoResponse.cs b/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetInfoResponse.cs new file mode 100644 index 000000000..1187f0c03 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonResponses/GetInfoResponse.cs @@ -0,0 +1,131 @@ +using System.Text.Json.Serialization; + +namespace Miningcore.Blockchain.Conceal.DaemonResponses; + +public record GetInfoResponse +{ + /// + /// Number of alternative blocks to main chain. + /// + [JsonPropertyName("alt_blocks_count")] + public int AltBlocksCount { get; set; } + + /// + /// ??? + /// + [JsonPropertyName("block_major_version")] + public int BlockMajorVersion { get; set; } + + /// + /// ??? + /// + [JsonPropertyName("block_minor_version")] + public int BlockMinorVersion { get; set; } + + /// + /// ??? + /// + [JsonPropertyName("connections")] + public string[] Connections { get; set; } + + /// + /// Network difficulty(analogous to the strength of the network) + /// + [JsonPropertyName("difficulty")] + public ulong Difficulty { get; set; } + + /// + /// (Optional) Address dedicated to smartnode rewards + /// + [JsonPropertyName("fee_address")] + public string FeeAddress { get; set; } = null; + + /// + /// Total amount deposit + /// + [JsonPropertyName("full_deposit_amount")] + public ulong FullAmountDeposit { get; set; } + + /// + /// Grey Peerlist Size + /// + [JsonPropertyName("grey_peerlist_size")] + public int GreyPeerlistSize { get; set; } + + /// + /// The height of the next block in the chain. + /// + [JsonPropertyName("height")] + public uint TargetHeight { get; set; } + + /// + /// Number of peers connected to and pulling from your node. + /// + [JsonPropertyName("incoming_connections_count")] + public int IncomingConnectionsCount { get; set; } + + /// + /// Last block difficulty + /// + [JsonPropertyName("last_block_difficulty")] + public ulong LastBlockDifficulty { get; set; } + + /// + /// Last block reward + /// + [JsonPropertyName("last_block_reward")] + public ulong LastBlockReward { get; set; } + + /// + /// Last block timestamp + /// + [JsonPropertyName("last_block_timestamp")] + public ulong LastBlockTimestamp { get; set; } + + /// + /// Current length of longest chain known to daemon. + /// + [JsonPropertyName("last_known_block_index")] + public uint Height { get; set; } + + /// + /// Number of peers that you are connected to and getting information from. + /// + [JsonPropertyName("outgoing_connections_count")] + public int OutgoingConnectionsCount { get; set; } + + /// + /// General RPC error code. "OK" means everything looks good. + /// + public string Status { get; set; } + + /// + /// Hash of the highest block in the chain. + /// + [JsonPropertyName("top_block_hash")] + public string TopBlockHash { get; set; } + + /// + /// Total number of non-coinbase transaction in the chain. + /// + [JsonPropertyName("tx_count")] + public uint TransactionCount { get; set; } + + /// + /// Number of transactions that have been broadcast but not included in a block. + /// + [JsonPropertyName("tx_pool_size")] + public uint TransactionPoolSize { get; set; } + + /// + /// Version + /// + [JsonPropertyName("version")] + public string Version { get; set; } + + /// + /// White Peerlist Size + /// + [JsonPropertyName("white_peerlist_size")] + public uint WhitePeerlistSize { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonResponses/SendTransactionResponse.cs b/src/Miningcore/Blockchain/Conceal/DaemonResponses/SendTransactionResponse.cs new file mode 100644 index 000000000..61ac6361a --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonResponses/SendTransactionResponse.cs @@ -0,0 +1,14 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.DaemonResponses; + +public class SendTransactionResponse +{ + /// + /// Publically searchable transaction hash + /// + [JsonProperty("transactionHash")] + public string TxHash { get; set; } + + public string Status { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonResponses/SplitIntegratedAddressResponse.cs b/src/Miningcore/Blockchain/Conceal/DaemonResponses/SplitIntegratedAddressResponse.cs new file mode 100644 index 000000000..4525ce68a --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonResponses/SplitIntegratedAddressResponse.cs @@ -0,0 +1,12 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.DaemonResponses; + +public class SplitIntegratedAddressResponse +{ + [JsonProperty("address")] + public string StandardAddress { get; set; } + + [JsonProperty("payment_id")] + public string Payment { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/DaemonResponses/SubmitResponse.cs b/src/Miningcore/Blockchain/Conceal/DaemonResponses/SubmitResponse.cs new file mode 100644 index 000000000..e69ff7ceb --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/DaemonResponses/SubmitResponse.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Conceal.DaemonResponses; + +public class SubmitResponse +{ + public string Status { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/StratumRequests/ConcealGetJobRequest.cs b/src/Miningcore/Blockchain/Conceal/StratumRequests/ConcealGetJobRequest.cs new file mode 100644 index 000000000..9be4e2d50 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/StratumRequests/ConcealGetJobRequest.cs @@ -0,0 +1,9 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.StratumRequests; + +public class ConcealGetJobRequest +{ + [JsonProperty("id")] + public string WorkerId { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/StratumRequests/ConcealLoginRequest.cs b/src/Miningcore/Blockchain/Conceal/StratumRequests/ConcealLoginRequest.cs new file mode 100644 index 000000000..5ba640914 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/StratumRequests/ConcealLoginRequest.cs @@ -0,0 +1,15 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.StratumRequests; + +public class ConcealLoginRequest +{ + [JsonProperty("login")] + public string Login { get; set; } + + [JsonProperty("pass")] + public string Password { get; set; } + + [JsonProperty("agent")] + public string UserAgent { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/StratumRequests/ConcealSubmitShareRequest.cs b/src/Miningcore/Blockchain/Conceal/StratumRequests/ConcealSubmitShareRequest.cs new file mode 100644 index 000000000..aa469ac1f --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/StratumRequests/ConcealSubmitShareRequest.cs @@ -0,0 +1,17 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.StratumRequests; + +public class ConcealSubmitShareRequest +{ + [JsonProperty("id")] + public string WorkerId { get; set; } + + [JsonProperty("job_id")] + public string JobId { get; set; } + + public string Nonce { get; set; } + + [JsonProperty("result")] + public string Hash { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/StratumResponses/ConcealLoginResponse.cs b/src/Miningcore/Blockchain/Conceal/StratumResponses/ConcealLoginResponse.cs new file mode 100644 index 000000000..a6e1c483d --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/StratumResponses/ConcealLoginResponse.cs @@ -0,0 +1,26 @@ +using Newtonsoft.Json; + +namespace Miningcore.Blockchain.Conceal.StratumResponses; + +public class ConcealJobParams +{ + [JsonProperty("job_id")] + public string JobId { get; set; } + + public string Blob { get; set; } + public string Target { get; set; } + + [JsonProperty("algo")] + public string Algorithm { get; set; } + + /// + /// Introduced for CNv4 (aka CryptonightR) + /// + public ulong Height { get; set; } +} + +public class ConcealLoginResponse : ConcealResponseBase +{ + public string Id { get; set; } = "1"; + public ConcealJobParams Job { get; set; } +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Conceal/StratumResponses/ConcealResponseBase.cs b/src/Miningcore/Blockchain/Conceal/StratumResponses/ConcealResponseBase.cs new file mode 100644 index 000000000..4425a9118 --- /dev/null +++ b/src/Miningcore/Blockchain/Conceal/StratumResponses/ConcealResponseBase.cs @@ -0,0 +1,6 @@ +namespace Miningcore.Blockchain.Conceal.StratumResponses; + +public class ConcealResponseBase +{ + public string Status { get; set; } = "OK"; +} \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs index cfb505ad6..a0ce6bdf3 100644 --- a/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs +++ b/src/Miningcore/Blockchain/Cryptonote/CryptonoteJob.cs @@ -35,26 +35,26 @@ public CryptonoteJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, { { CryptonightHashType.RandomX, (realm, seedHex, data, result, _) => RandomX.CalculateHash(realm, seedHex, data, result) }, { CryptonightHashType.RandomARQ, (realm, seedHex, data, result, _) => RandomARQ.CalculateHash(realm, seedHex, data, result) }, - { CryptonightHashType.Crytonight0, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_0, height) }, - { CryptonightHashType.Crytonight1, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_1, height) }, - { CryptonightHashType.Crytonight2, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_2, height) }, - { CryptonightHashType.CrytonightHalf, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_HALF, height) }, - { CryptonightHashType.CrytonightDouble, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_DOUBLE, height) }, - { CryptonightHashType.CrytonightR, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_R, height) }, - { CryptonightHashType.CrytonightRTO, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_RTO, height) }, - { CryptonightHashType.CrytonightRWZ, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_RWZ, height) }, - { CryptonightHashType.CrytonightZLS, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_ZLS, height) }, - { CryptonightHashType.CrytonightCCX, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_CCX, height) }, - { CryptonightHashType.CrytonightGPU, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_GPU, height) }, - { CryptonightHashType.CrytonightFast, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_FAST, height) }, - { CryptonightHashType.CrytonightXAO, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_XAO, height) }, + { CryptonightHashType.Cryptonight0, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_0, height) }, + { CryptonightHashType.Cryptonight1, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_1, height) }, + { CryptonightHashType.Cryptonight2, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_2, height) }, + { CryptonightHashType.CryptonightHalf, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_HALF, height) }, + { CryptonightHashType.CryptonightDouble, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_DOUBLE, height) }, + { CryptonightHashType.CryptonightR, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_R, height) }, + { CryptonightHashType.CryptonightRTO, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_RTO, height) }, + { CryptonightHashType.CryptonightRWZ, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_RWZ, height) }, + { CryptonightHashType.CryptonightZLS, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_ZLS, height) }, + { CryptonightHashType.CryptonightCCX, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_CCX, height) }, + { CryptonightHashType.CryptonightGPU, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_GPU, height) }, + { CryptonightHashType.CryptonightFast, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_FAST, height) }, + { CryptonightHashType.CryptonightXAO, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_XAO, height) }, { CryptonightHashType.Ghostrider, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, GHOSTRIDER_RTM, height) }, - { CryptonightHashType.CrytonightLite0, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_LITE_0, height) }, - { CryptonightHashType.CrytonightLite1, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_LITE_1, height) }, - { CryptonightHashType.CrytonightHeavy, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_HEAVY_0, height) }, - { CryptonightHashType.CrytonightHeavyXHV, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_HEAVY_XHV, height) }, - { CryptonightHashType.CrytonightHeavyTube, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_HEAVY_TUBE, height) }, - { CryptonightHashType.CrytonightPico, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_PICO_0, height) }, + { CryptonightHashType.CryptonightLite0, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_LITE_0, height) }, + { CryptonightHashType.CryptonightLite1, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_LITE_1, height) }, + { CryptonightHashType.CryptonightHeavy, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_HEAVY_0, height) }, + { CryptonightHashType.CryptonightHeavyXHV, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_HEAVY_XHV, height) }, + { CryptonightHashType.CryptonightHeavyTube, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_HEAVY_TUBE, height) }, + { CryptonightHashType.CryptonightPico, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, CN_PICO_0, height) }, { CryptonightHashType.ArgonCHUKWA, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, AR2_CHUKWA, height) }, { CryptonightHashType.ArgonCHUKWAV2, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, AR2_CHUKWA_V2, height) }, { CryptonightHashType.ArgonWRKZ, (_, _, data, result, height) => Cryptonight.CryptonightHash(data, result, AR2_WRKZ, height) }, diff --git a/src/Miningcore/Blockchain/Ethereum/DaemonRequests/SendTransactionRequest.cs b/src/Miningcore/Blockchain/Ethereum/DaemonRequests/SendTransactionRequest.cs index 4494b9440..6fd948d50 100644 --- a/src/Miningcore/Blockchain/Ethereum/DaemonRequests/SendTransactionRequest.cs +++ b/src/Miningcore/Blockchain/Ethereum/DaemonRequests/SendTransactionRequest.cs @@ -42,16 +42,18 @@ public class SendTransactionRequest public string Data { get; set; } /// - /// Maximum fee per gas the sender is willing to pay to miners in wei. + /// (Optional) Maximum fee per gas the sender is willing to pay to miners in wei / Only available if LONDON Fork is active on the network /// [JsonConverter(typeof(HexToIntegralTypeJsonConverter))] - public ulong MaxPriorityFeePerGas { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public ulong? MaxPriorityFeePerGas { get; set; } /// - /// The maximum total fee per gas the sender is willing to pay(includes the network / base fee and miner / priority fee) in wei + /// (Optional) The maximum total fee per gas the sender is willing to pay(includes the network / base fee and miner / priority fee) in wei / Only available if LONDON Fork is active on the network /// [JsonConverter(typeof(HexToIntegralTypeJsonConverter))] - public ulong MaxFeePerGas { get; set; } + [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] + public ulong? MaxFeePerGas { get; set; } } diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs b/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs index 79794f11e..10a9c31dc 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumConstants.cs @@ -39,6 +39,19 @@ public class EthereumConstants public const string RpcRequestWorkerPropertyName = "worker"; } +// ETC block reward distribution - ECIP 1017 +// https://ecips.ethereumclassic.org/ECIPs/ecip-1017 +public class EthereumClassicConstants +{ + public const ulong HardForkBlockMainnet = 11700000; + public const ulong HardForkBlockMordor = 2520000; + public const ulong EpochLength = 60000; + public const ulong EraLength = 5000001; + public const double DisinflationRateQuotient = 4.0; + public const double DisinflationRateDivisor = 5.0; + public const decimal BaseRewardInitial = 5.0m; +} + // Callisto Monetary Policy // https://github.com/EthereumCommonwealth/Roadmap/issues/56 public class CallistoConstants @@ -57,10 +70,30 @@ public class PinkConstants public const decimal BaseRewardInitial = 1.0m; } +// UBIQ block reward distribution - +// https://github.com/ubiq/UIPs/issues/16 - https://ubiqsmart.com/en/monetary-policy +public class UbiqConstants +{ + public const ulong YearOneHeight = 358363; + public const decimal YearOneBlockReward = 7.0m; + public const ulong YearTwoHeight = 716727; + public const decimal YearTwoBlockReward = 6.0m; + public const ulong YearThreeHeight = 1075090; + public const decimal YearThreeBlockReward = 5.0m; + public const ulong YearFourHeight = 1433454; + public const decimal YearFourBlockReward = 4.0m; + public const ulong OrionHardForkHeight = 1791793; + public const decimal OrionBlockReward = 1.5m; + public const decimal BaseRewardInitial = 8.0m; +} + public enum EthereumNetworkType { Main = 1, Ropsten = 3, + Ubiq = 8, + Classic = 1, + Mordor = 7, Callisto = 820, MainPow = 10001, EtherOne = 4949, @@ -73,6 +106,9 @@ public enum GethChainType { Main, Ropsten, + Ubiq, + Classic, + Mordor, Callisto, MainPow = 10001, EtherOne = 4949, diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs index b6bea405b..a7a181e49 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJob.cs @@ -1,6 +1,8 @@ using System.Globalization; using System.Numerics; +using Miningcore.Crypto.Hashing.Etchash; using Miningcore.Crypto.Hashing.Ethash; +using Miningcore.Crypto.Hashing.Ubqhash; using Miningcore.Extensions; using Miningcore.Stratum; using NBitcoin; @@ -50,6 +52,79 @@ private void RegisterNonce(StratumConnection worker, string nonce) nonces.Add(nonceLower); } } + + public async Task ProcessShareEtcHashAsync(StratumConnection worker, + string workerName, string fullNonceHex, EtchashFull etchash, CancellationToken ct) + { + // dupe check + lock(workerNonces) + { + RegisterNonce(worker, fullNonceHex); + } + + var context = worker.ContextAs(); + + if(!ulong.TryParse(fullNonceHex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var fullNonce)) + throw new StratumException(StratumError.MinusOne, "bad nonce " + fullNonceHex); + + // get dag for block + var dag = await etchash.GetDagAsync(BlockTemplate.Height, logger, CancellationToken.None); + + // compute + if(!dag.Compute(logger, BlockTemplate.Header.HexToByteArray(), fullNonce, out var mixDigest, out var resultBytes)) + throw new StratumException(StratumError.MinusOne, "bad hash"); + + // test if share meets at least workers current difficulty + resultBytes.ReverseInPlace(); + var resultValue = new uint256(resultBytes); + var resultValueBig = resultBytes.AsSpan().ToBigInteger(); + var shareDiff = (double) BigInteger.Divide(EthereumConstants.BigMaxValue, resultValueBig) / EthereumConstants.Pow2x32; + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + var isBlockCandidate = resultValue <= blockTarget; + + if(!isBlockCandidate && ratio < 0.99) + { + // check if share matched the previous difficulty from before a vardiff retarget + if(context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue) + { + ratio = shareDiff / context.PreviousDifficulty.Value; + + if(ratio < 0.99) + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + + // use previous difficulty + stratumDifficulty = context.PreviousDifficulty.Value; + } + + else + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + } + + var share = new Share + { + BlockHeight = (long) BlockTemplate.Height, + IpAddress = worker.RemoteEndpoint?.Address?.ToString(), + Miner = context.Miner, + Worker = workerName, + UserAgent = context.UserAgent, + IsBlockCandidate = isBlockCandidate, + Difficulty = stratumDifficulty * EthereumConstants.Pow2x32 + }; + + if(share.IsBlockCandidate) + { + fullNonceHex = "0x" + fullNonceHex; + var headerHash = BlockTemplate.Header; + var mixHash = mixDigest.ToHexString(true); + + share.TransactionConfirmationData = ""; + + return new SubmitResult(share, fullNonceHex, headerHash, mixHash); + } + + return new SubmitResult(share); + } public async Task ProcessShareAsync(StratumConnection worker, string workerName, string fullNonceHex, EthashFull ethash, CancellationToken ct) @@ -123,6 +198,79 @@ public async Task ProcessShareAsync(StratumConnection worker, return new SubmitResult(share); } + + public async Task ProcessShareUbqHashAsync(StratumConnection worker, + string workerName, string fullNonceHex, UbqhashFull ubqhash, CancellationToken ct) + { + // dupe check + lock(workerNonces) + { + RegisterNonce(worker, fullNonceHex); + } + + var context = worker.ContextAs(); + + if(!ulong.TryParse(fullNonceHex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var fullNonce)) + throw new StratumException(StratumError.MinusOne, "bad nonce " + fullNonceHex); + + // get dag for block + var dag = await ubqhash.GetDagAsync(BlockTemplate.Height, logger, CancellationToken.None); + + // compute + if(!dag.Compute(logger, BlockTemplate.Header.HexToByteArray(), fullNonce, out var mixDigest, out var resultBytes)) + throw new StratumException(StratumError.MinusOne, "bad hash"); + + // test if share meets at least workers current difficulty + resultBytes.ReverseInPlace(); + var resultValue = new uint256(resultBytes); + var resultValueBig = resultBytes.AsSpan().ToBigInteger(); + var shareDiff = (double) BigInteger.Divide(EthereumConstants.BigMaxValue, resultValueBig) / EthereumConstants.Pow2x32; + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; + var isBlockCandidate = resultValue <= blockTarget; + + if(!isBlockCandidate && ratio < 0.99) + { + // check if share matched the previous difficulty from before a vardiff retarget + if(context.VarDiff?.LastUpdate != null && context.PreviousDifficulty.HasValue) + { + ratio = shareDiff / context.PreviousDifficulty.Value; + + if(ratio < 0.99) + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + + // use previous difficulty + stratumDifficulty = context.PreviousDifficulty.Value; + } + + else + throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + } + + var share = new Share + { + BlockHeight = (long) BlockTemplate.Height, + IpAddress = worker.RemoteEndpoint?.Address?.ToString(), + Miner = context.Miner, + Worker = workerName, + UserAgent = context.UserAgent, + IsBlockCandidate = isBlockCandidate, + Difficulty = stratumDifficulty * EthereumConstants.Pow2x32 + }; + + if(share.IsBlockCandidate) + { + fullNonceHex = "0x" + fullNonceHex; + var headerHash = BlockTemplate.Header; + var mixHash = mixDigest.ToHexString(true); + + share.TransactionConfirmationData = ""; + + return new SubmitResult(share, fullNonceHex, headerHash, mixHash); + } + + return new SubmitResult(share); + } public object[] GetJobParamsForStratum() { diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs index 2996bef71..e1a82b769 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumJobManager.cs @@ -8,7 +8,9 @@ using Miningcore.Blockchain.Ethereum.Configuration; using Miningcore.Blockchain.Ethereum.DaemonResponses; using Miningcore.Configuration; +using Miningcore.Crypto.Hashing.Etchash; using Miningcore.Crypto.Hashing.Ethash; +using Miningcore.Crypto.Hashing.Ubqhash; using Miningcore.Extensions; using Miningcore.JsonRpc; using Miningcore.Messaging; @@ -50,7 +52,9 @@ public EthereumJobManager( private RpcClient rpc; private EthereumNetworkType networkType; private GethChainType chainType; + private EtchashFull etchash; private EthashFull ethash; + private UbqhashFull ubqhash; private readonly IMasterClock clock; private readonly IExtraNonceProvider extraNonceProvider; private const int MaxBlockBacklog = 6; @@ -345,16 +349,50 @@ public override void Configure(PoolConfig pc, ClusterConfig cc) if(pc.EnableInternalStratum == true) { + var coin = pc.Template.As(); + // ensure dag location is configured - var dagDir = !string.IsNullOrEmpty(extraPoolConfig?.DagDir) ? - Environment.ExpandEnvironmentVariables(extraPoolConfig.DagDir) : - Dag.GetDefaultDagDirectory(); + string dagDir = null; + + if(!string.IsNullOrEmpty(extraPoolConfig?.DagDir)) + { + dagDir = Environment.ExpandEnvironmentVariables(extraPoolConfig.DagDir); + } + else + { + // Default DAG folder + switch(coin.Symbol) + { + case "ETC": + dagDir = DagEtchash.GetDefaultDagDirectory(); + break; + case "UBIQ": + dagDir = DagUbqhash.GetDefaultDagDirectory(); + break; + default: + dagDir = Dag.GetDefaultDagDirectory(); + break; + } + } // create it if necessary Directory.CreateDirectory(dagDir); // setup ethash - ethash = new EthashFull(3, dagDir); + switch(coin.Symbol) + { + case "ETC": + var hardForkBlock = extraPoolConfig?.ChainTypeOverride == "Classic" ? EthereumClassicConstants.HardForkBlockMainnet : EthereumClassicConstants.HardForkBlockMordor; + logger.Debug(() => $"Hard fork block on `{extraPoolConfig?.ChainTypeOverride}`: {hardForkBlock}"); + etchash = new EtchashFull(3, dagDir, hardForkBlock); + break; + case "UBIQ": + ubqhash = new UbqhashFull(3, dagDir); + break; + default: + ethash = new EthashFull(3, dagDir); + break; + } } } @@ -427,31 +465,87 @@ public async Task SubmitShareV2Async(StratumConnection worker, string[] r private async Task SubmitShareAsync(StratumConnection worker, EthereumWorkerContext context, string workerName, EthereumJob job, string nonce, CancellationToken ct) { + var coin = poolConfig.Template.As(); + // validate & process - var (share, fullNonceHex, headerHash, mixHash) = await job.ProcessShareAsync(worker, workerName, nonce, ethash, ct); + switch(coin.Symbol) + { + case "ETC": + var (shareEtchash, fullNonceHexEtchash, headerHashEtchash, mixHashEtchash) = await job.ProcessShareEtcHashAsync(worker, workerName, nonce, etchash, ct); + + // enrich share with common data + shareEtchash.PoolId = poolConfig.Id; + shareEtchash.NetworkDifficulty = BlockchainStats.NetworkDifficulty; + shareEtchash.Source = clusterConfig.ClusterName; + shareEtchash.Created = clock.Now; + + // if block candidate, submit & check if accepted by network + if(shareEtchash.IsBlockCandidate) + { + logger.Info(() => $"Submitting block {shareEtchash.BlockHeight}"); - // enrich share with common data - share.PoolId = poolConfig.Id; - share.NetworkDifficulty = BlockchainStats.NetworkDifficulty; - share.Source = clusterConfig.ClusterName; - share.Created = clock.Now; + shareEtchash.IsBlockCandidate = await SubmitBlockAsync(shareEtchash, fullNonceHexEtchash, headerHashEtchash, mixHashEtchash); - // if block candidate, submit & check if accepted by network - if(share.IsBlockCandidate) - { - logger.Info(() => $"Submitting block {share.BlockHeight}"); + if(shareEtchash.IsBlockCandidate) + { + logger.Info(() => $"Daemon accepted block {shareEtchash.BlockHeight} submitted by {context.Miner}"); + + OnBlockFound(); + } + } + + return shareEtchash; + case "UBIQ": + var (shareUbqhash, fullNonceHexUbqhash, headerHashUbqhash, mixHashUbqhash) = await job.ProcessShareUbqHashAsync(worker, workerName, nonce, ubqhash, ct); + + // enrich share with common data + shareUbqhash.PoolId = poolConfig.Id; + shareUbqhash.NetworkDifficulty = BlockchainStats.NetworkDifficulty; + shareUbqhash.Source = clusterConfig.ClusterName; + shareUbqhash.Created = clock.Now; + + // if block candidate, submit & check if accepted by network + if(shareUbqhash.IsBlockCandidate) + { + logger.Info(() => $"Submitting block {shareUbqhash.BlockHeight}"); - share.IsBlockCandidate = await SubmitBlockAsync(share, fullNonceHex, headerHash, mixHash); + shareUbqhash.IsBlockCandidate = await SubmitBlockAsync(shareUbqhash, fullNonceHexUbqhash, headerHashUbqhash, mixHashUbqhash); - if(share.IsBlockCandidate) - { - logger.Info(() => $"Daemon accepted block {share.BlockHeight} submitted by {context.Miner}"); + if(shareUbqhash.IsBlockCandidate) + { + logger.Info(() => $"Daemon accepted block {shareUbqhash.BlockHeight} submitted by {context.Miner}"); - OnBlockFound(); - } - } + OnBlockFound(); + } + } + + return shareUbqhash; + default: + var (share, fullNonceHex, headerHash, mixHash) = await job.ProcessShareAsync(worker, workerName, nonce, ethash, ct); + + // enrich share with common data + share.PoolId = poolConfig.Id; + share.NetworkDifficulty = BlockchainStats.NetworkDifficulty; + share.Source = clusterConfig.ClusterName; + share.Created = clock.Now; + + // if block candidate, submit & check if accepted by network + if(share.IsBlockCandidate) + { + logger.Info(() => $"Submitting block {share.BlockHeight}"); + + share.IsBlockCandidate = await SubmitBlockAsync(share, fullNonceHex, headerHash, mixHash); - return share; + if(share.IsBlockCandidate) + { + logger.Info(() => $"Daemon accepted block {share.BlockHeight} submitted by {context.Miner}"); + + OnBlockFound(); + } + } + + return share; + } } public BlockchainStats BlockchainStats { get; } = new(); @@ -534,6 +628,7 @@ protected override async Task PostStartInitAsync(CancellationToken ct) // var accounts = responses[1].Response.ToObject(); // var coinbase = responses[2].Response.ToObject(); var gethChain = extraPoolConfig?.ChainTypeOverride ?? "Ethereum"; + var coin = poolConfig.Template.As(); EthereumUtils.DetectNetworkAndChain(netVersion, gethChain, out networkType, out chainType); @@ -563,9 +658,21 @@ protected override async Task PostStartInitAsync(CancellationToken ct) if(blockTemplate != null) { logger.Info(() => "Loading current DAG ..."); - - await ethash.GetDagAsync(blockTemplate.Height, logger, ct); - + + // setup dag file + switch(coin.Symbol) + { + case "ETC": + await etchash.GetDagAsync(blockTemplate.Height, logger, ct); + break; + case "UBIQ": + await ubqhash.GetDagAsync(blockTemplate.Height, logger, ct); + break; + default: + await ethash.GetDagAsync(blockTemplate.Height, logger, ct); + break; + } + logger.Info(() => "Loaded current DAG"); break; } diff --git a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs index 159a30873..bb98c7c7f 100644 --- a/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs +++ b/src/Miningcore/Blockchain/Ethereum/EthereumPayoutHandler.cs @@ -110,39 +110,76 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, result.Add(block); messageBus.NotifyBlockConfirmationProgress(poolConfig.Id, block, coin); - + // is it block mined by us? if(string.Equals(blockInfo.Miner, poolConfig.Address, StringComparison.OrdinalIgnoreCase)) { // mature? if(latestBlockHeight - block.BlockHeight >= EthereumConstants.MinConfimations) { - var blockHashResponse = await rpcClient.ExecuteAsync(logger, EC.GetBlockByNumber, ct, - new[] { (object) block.BlockHeight.ToStringHexWithPrefix(), true }); - var blockHash = blockHashResponse.Response.Hash; - var baseGas = blockHashResponse.Response.BaseFeePerGas; - var gasUsed = blockHashResponse.Response.GasUsed; + // There is a case scenario: + // - https://github.com/oliverw/miningcore/issues/1583#issuecomment-1383009149 + // - https://github.com/oliverw/miningcore/discussions/1103#discussioncomment-2121240) + // Where a miner with enough hash-rate power is able to mine two blocks simultaneously with the same `height` + // The first block is always an uncle and the second block is a regular block + // We must handle that case carefully here, otherwise the PayoutManager will crash and no further blocks will be unlocked and no payment will be sent anymore. + + uint totalDuplicateBlock = await cf.Run(con => blockRepo.GetPoolDuplicateBlockCountByPoolHeightNoTypeAndStatusAsync(con, poolConfig.Id, Convert.ToInt64(block.BlockHeight), new[] + { + block.Status + })); + uint totalDuplicateBlockBefore = 0; + + if(totalDuplicateBlock > 1) + { + totalDuplicateBlockBefore = await cf.Run(con => blockRepo.GetPoolDuplicateBlockBeforeCountByPoolHeightNoTypeAndStatusAsync(con, poolConfig.Id, Convert.ToInt64(block.BlockHeight), new[] + { + block.Status + }, block.Created)); + } + + if(totalDuplicateBlock > 1 && totalDuplicateBlockBefore < 1) + { + logger.Info(() => $"[{LogCategory}] Got {totalDuplicateBlock} `{block.Status}` blocks with the same blockHeight: {block.BlockHeight}"); + + block.Reward = GetUncleReward(chainType, block.BlockHeight, block.BlockHeight); + block.Status = BlockStatus.Confirmed; + block.ConfirmationProgress = 1; + block.BlockHeight = (ulong) blockInfo.Height; + block.Type = EthereumConstants.BlockTypeUncle; + + logger.Info(() => $"[{LogCategory}] Unlocked uncle at height {block.BlockHeight} worth {FormatAmount(block.Reward)}"); + + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } + else { + var blockHashResponse = await rpcClient.ExecuteAsync(logger, EC.GetBlockByNumber, ct, + new[] { (object) block.BlockHeight.ToStringHexWithPrefix(), true }); + var blockHash = blockHashResponse.Response.Hash; + var baseGas = blockHashResponse.Response.BaseFeePerGas; + var gasUsed = blockHashResponse.Response.GasUsed; - var burnedFee = (decimal) 0; - if(extraPoolConfig?.ChainTypeOverride == "Ethereum" || extraPoolConfig?.ChainTypeOverride == "Main" || extraPoolConfig?.ChainTypeOverride == "MainPow" || extraPoolConfig?.ChainTypeOverride == "EtherOne" || extraPoolConfig?.ChainTypeOverride == "Pink") - burnedFee = (baseGas * gasUsed / EthereumConstants.Wei); + var burnedFee = (decimal) 0; + if(extraPoolConfig?.ChainTypeOverride == "Ethereum" || extraPoolConfig?.ChainTypeOverride == "Main" || extraPoolConfig?.ChainTypeOverride == "MainPow" || extraPoolConfig?.ChainTypeOverride == "Ubiq" || extraPoolConfig?.ChainTypeOverride == "EtherOne" || extraPoolConfig?.ChainTypeOverride == "Pink") + burnedFee = (baseGas * gasUsed / EthereumConstants.Wei); - block.Hash = blockHash; - block.Status = BlockStatus.Confirmed; - block.ConfirmationProgress = 1; - block.BlockHeight = (ulong) blockInfo.Height; - block.Reward = GetBaseBlockReward(chainType, block.BlockHeight); // base reward - block.Type = EthereumConstants.BlockTypeBlock; + block.Hash = blockHash; + block.Status = BlockStatus.Confirmed; + block.ConfirmationProgress = 1; + block.BlockHeight = (ulong) blockInfo.Height; + block.Reward = GetBaseBlockReward(chainType, block.BlockHeight); // base reward + block.Type = EthereumConstants.BlockTypeBlock; - if(extraConfig?.KeepUncles == false) - block.Reward += blockInfo.Uncles.Length * (block.Reward / 32); // uncle rewards + if(extraConfig?.KeepUncles == false) + block.Reward += blockInfo.Uncles.Length * (block.Reward / 32); // uncle rewards - if(extraConfig?.KeepTransactionFees == false && blockInfo.Transactions?.Length > 0) - block.Reward += await GetTxRewardAsync(blockInfo, ct) - burnedFee; + if(extraConfig?.KeepTransactionFees == false && blockInfo.Transactions?.Length > 0) + block.Reward += await GetTxRewardAsync(blockInfo, ct) - burnedFee; - logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); + logger.Info(() => $"[{LogCategory}] Unlocked block {block.BlockHeight} worth {FormatAmount(block.Reward)}"); - messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + messageBus.NotifyBlockUnlocked(poolConfig.Id, block, coin); + } } continue; @@ -151,6 +188,9 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, // search for a block containing our block as an uncle by checking N blocks in either direction var heightMin = block.BlockHeight - extraConfig.BlockSearchOffset; var heightMax = Math.Min(block.BlockHeight + extraConfig.BlockSearchOffset, latestBlockHeight); + + logger.Debug(() => $"[{LogCategory}] BlockSearchOffset used: {extraConfig.BlockSearchOffset} - Range of blockHeight searched - Min: {heightMin}, Max: {heightMax}"); + var range = new List(); for(var k = heightMin; k < heightMax; k++) @@ -194,13 +234,14 @@ public async Task ClassifyBlocksAsync(IMiningPool pool, Block[] blocks, // This is not always the case, so we need to check the DB for any other // uncles from that block and continue searching if there any others. // Otherwise the payouter will crash and no further blocks will be unlocked. - var duplBlock = await cf.Run(con => blockRepo.GetBlockByHeightAsync(con, poolConfig.Id, Convert.ToInt64(uncle.Height.Value))); - if(duplBlock != null && duplBlock.Type == EthereumConstants.BlockTypeUncle) + var uncleBlock = await cf.Run(con => blockRepo.GetBlockByPoolHeightAndTypeAsync(con, poolConfig.Id, Convert.ToInt64(uncle.Height.Value), EthereumConstants.BlockTypeUncle)); + if(uncleBlock != null) { logger.Info(() => $"[{LogCategory}] Found another uncle from block {uncle.Height.Value} in the DB. Continuing search for uncle."); continue; } - + + block.Hash = uncle.Hash; block.Reward = GetUncleReward(chainType, uncle.Height.Value, blockInfo2.Height.Value); block.Status = BlockStatus.Confirmed; block.ConfirmationProgress = 1; @@ -250,7 +291,7 @@ public async Task PayoutAsync(IMiningPool pool, Balance[] balances, Cancellation // ensure we have peers var infoResponse = await rpcClient.ExecuteAsync(logger, EC.GetPeerCount, ct); - if((networkType == EthereumNetworkType.Main || networkType == EthereumNetworkType.MainPow || extraPoolConfig?.ChainTypeOverride == "EtherOne" || extraPoolConfig?.ChainTypeOverride == "Pink") && + if((networkType == EthereumNetworkType.Main || extraPoolConfig?.ChainTypeOverride == "Classic" || extraPoolConfig?.ChainTypeOverride == "Mordor" || networkType == EthereumNetworkType.MainPow || extraPoolConfig?.ChainTypeOverride == "Ubiq" || extraPoolConfig?.ChainTypeOverride == "EtherOne" || extraPoolConfig?.ChainTypeOverride == "Pink") && (infoResponse.Error != null || string.IsNullOrEmpty(infoResponse.Response) || infoResponse.Response.IntegralFromHex() < EthereumConstants.MinPayoutPeerCount)) { @@ -327,16 +368,39 @@ internal static decimal GetBaseBlockReward(GethChainType chainType, ulong height return EthereumConstants.ByzantiumBlockReward; return EthereumConstants.HomesteadBlockReward; - + + case GethChainType.Classic: + case GethChainType.Mordor: + // ETC block reward distribution - ECIP 1017 - https://ecips.ethereumclassic.org/ECIPs/ecip-1017 + double heightEraLength = height / EthereumClassicConstants.EraLength; + double era = Math.Truncate(heightEraLength); + decimal quotient = Convert.ToDecimal(Math.Pow(EthereumClassicConstants.DisinflationRateQuotient, era)); + decimal divisor = Convert.ToDecimal(Math.Pow(EthereumClassicConstants.DisinflationRateDivisor, era)); + return ((EthereumClassicConstants.BaseRewardInitial * quotient) / divisor); + case GethChainType.EtherOne: return EthOneConstants.BaseRewardInitial; - + case GethChainType.Pink: return PinkConstants.BaseRewardInitial; case GethChainType.Callisto: return CallistoConstants.BaseRewardInitial * (CallistoConstants.TreasuryPercent / 100); - + + case GethChainType.Ubiq: + if(height >= UbiqConstants.OrionHardForkHeight) + return UbiqConstants.OrionBlockReward; + if(height >= UbiqConstants.YearFourHeight) + return UbiqConstants.YearFourBlockReward; + if(height >= UbiqConstants.YearThreeHeight) + return UbiqConstants.YearThreeBlockReward; + if(height >= UbiqConstants.YearTwoHeight) + return UbiqConstants.YearTwoBlockReward; + if(height >= UbiqConstants.YearOneHeight) + return UbiqConstants.YearOneBlockReward; + + return UbiqConstants.BaseRewardInitial; + default: throw new Exception("Unable to determine block reward: Unsupported chain type"); } @@ -366,10 +430,37 @@ private async Task GetTxRewardAsync(DaemonResponses.Block blockInfo, Ca internal static decimal GetUncleReward(GethChainType chainType, ulong uheight, ulong height) { var reward = GetBaseBlockReward(chainType, height); - - reward *= uheight + 8 - height; - reward /= 8m; - + + switch(chainType) + { + case GethChainType.Classic: + case GethChainType.Mordor: + double heightEraLength = height / EthereumClassicConstants.EraLength; + double era = Math.Floor(heightEraLength); + if (era == 0) { + reward *= uheight + 8 - height; + reward /= 8m; + } + else { + reward /= 32m; + } + + break; + case GethChainType.Ubiq: + reward *= uheight + 2 - height; + reward /= 2m; + // blocks older than the previous block are not rewarded + if (reward < 0) + reward = 0; + + break; + default: + reward *= uheight + 8 - height; + reward /= 8m; + + break; + } + return reward; } @@ -411,13 +502,40 @@ private async Task PayoutAsync(Balance balance, CancellationToken ct) To = balance.Address, Value = amount.ToString("x").TrimStart('0'), }; - - if(extraPoolConfig?.ChainTypeOverride == "Ethereum" || extraPoolConfig?.ChainTypeOverride == "Main" || extraPoolConfig?.ChainTypeOverride == "MainPow" || extraPoolConfig?.ChainTypeOverride == "EtherOne" ) + + if(extraPoolConfig?.ChainTypeOverride == "Ethereum" || extraPoolConfig?.ChainTypeOverride == "Main" || (extraPoolConfig?.ChainTypeOverride == "Ubiq") || extraPoolConfig?.ChainTypeOverride == "MainPow" || extraPoolConfig?.ChainTypeOverride == "EtherOne" ) { var maxPriorityFeePerGas = await rpcClient.ExecuteAsync(logger, EC.MaxPriorityFeePerGas, ct); - request.Gas = extraConfig.Gas; - request.MaxPriorityFeePerGas = maxPriorityFeePerGas.Response.IntegralFromHex(); - request.MaxFeePerGas = extraConfig.MaxFeePerGas; + + logger.Debug(() => $"[{LogCategory}] MaxPriorityFeePerGas: {maxPriorityFeePerGas.Response.IntegralFromHex()} Wei"); + + if(extraPoolConfig?.ChainTypeOverride == "Ubiq") + { + // get latest block + var latestBlockResponse = await rpcClient.ExecuteAsync(logger, EC.GetBlockByNumber, ct, new[] { (object) "latest", true }); + var latestBlockHeight = latestBlockResponse.Response.Height.Value; + + // EIP-1559 Transaction + if(latestBlockHeight >= UbiqConstants.OrionHardForkHeight) + { + logger.Debug(() => $"[{LogCategory}] Transaction (EIP-1559)"); + + request.Gas = extraConfig.Gas; + request.MaxPriorityFeePerGas = maxPriorityFeePerGas.Response.IntegralFromHex(); + } + // Legacy Transaction + else { + logger.Debug(() => $"[{LogCategory}] Transaction (Legacy)"); + + request.Gas = extraConfig.Gas; + request.GasPrice = extraConfig.MaxFeePerGas; + } + } + else { + request.Gas = extraConfig.Gas; + request.MaxPriorityFeePerGas = maxPriorityFeePerGas.Response.IntegralFromHex(); + request.MaxFeePerGas = extraConfig.MaxFeePerGas; + } } RpcResponse response; @@ -431,17 +549,17 @@ private async Task PayoutAsync(Balance balance, CancellationToken ct) Gas = extraConfig.Gas }; response = await rpcClient.ExecuteAsync(logger, EC.SendTx, ct, new[] { requestPink }); - } + } else { response = await rpcClient.ExecuteAsync(logger, EC.SendTx, ct, new[] { request }); } if(response.Error != null) throw new Exception($"{EC.SendTx} returned error: {response.Error.Message} code {response.Error.Code}"); - + if(string.IsNullOrEmpty(response.Response) || EthereumConstants.ZeroHashPattern.IsMatch(response.Response)) throw new Exception($"{EC.SendTx} did not return a valid transaction hash"); - + var txHash = response.Response; logger.Info(() => $"[{LogCategory}] Payment transaction id: {txHash}"); diff --git a/src/Miningcore/Configuration/ClusterConfig.cs b/src/Miningcore/Configuration/ClusterConfig.cs index d430976d1..0fa3c07ad 100644 --- a/src/Miningcore/Configuration/ClusterConfig.cs +++ b/src/Miningcore/Configuration/ClusterConfig.cs @@ -22,6 +22,9 @@ public enum CoinFamily [EnumMember(Value = "equihash")] Equihash, + [EnumMember(Value = "conceal")] + Conceal, + [EnumMember(Value = "cryptonote")] Cryptonote, @@ -129,6 +132,7 @@ public abstract partial class CoinTemplate { {CoinFamily.Bitcoin, typeof(BitcoinTemplate)}, {CoinFamily.Equihash, typeof(EquihashCoinTemplate)}, + {CoinFamily.Conceal, typeof(ConcealCoinTemplate)}, {CoinFamily.Cryptonote, typeof(CryptonoteCoinTemplate)}, {CoinFamily.Ethereum, typeof(EthereumCoinTemplate)}, {CoinFamily.Ergo, typeof(ErgoCoinTemplate)}, @@ -322,6 +326,12 @@ public partial class EquihashNetworkParams public bool UseBitcoinPayoutHandler { get; set; } } +public enum ConcealSubfamily +{ + [EnumMember(Value = "none")] + None, +} + public enum CryptonoteSubfamily { [EnumMember(Value = "none")] @@ -337,64 +347,64 @@ public enum CryptonightHashType RandomARQ, [EnumMember(Value = "cn0")] - Crytonight0, + Cryptonight0, [EnumMember(Value = "cn1")] - Crytonight1, + Cryptonight1, [EnumMember(Value = "cn2")] - Crytonight2, + Cryptonight2, [EnumMember(Value = "cn-half")] - CrytonightHalf, + CryptonightHalf, [EnumMember(Value = "cn-double")] - CrytonightDouble, + CryptonightDouble, [EnumMember(Value = "cn-r")] - CrytonightR, + CryptonightR, [EnumMember(Value = "cn-rto")] - CrytonightRTO, + CryptonightRTO, [EnumMember(Value = "cn-rwz")] - CrytonightRWZ, + CryptonightRWZ, [EnumMember(Value = "cn-zls")] - CrytonightZLS, + CryptonightZLS, [EnumMember(Value = "cn-ccx")] - CrytonightCCX, + CryptonightCCX, [EnumMember(Value = "cn-gpu")] - CrytonightGPU, + CryptonightGPU, [EnumMember(Value = "cn-fast")] - CrytonightFast, + CryptonightFast, [EnumMember(Value = "cn-xao")] - CrytonightXAO, + CryptonightXAO, [EnumMember(Value = "gr")] Ghostrider, [EnumMember(Value = "cn_lite0")] - CrytonightLite0, + CryptonightLite0, [EnumMember(Value = "cn_lite1")] - CrytonightLite1, + CryptonightLite1, [EnumMember(Value = "cn_heavy")] - CrytonightHeavy, + CryptonightHeavy, [EnumMember(Value = "cn_heavy_xhv")] - CrytonightHeavyXHV, + CryptonightHeavyXHV, [EnumMember(Value = "cn_heavy_tube")] - CrytonightHeavyTube, + CryptonightHeavyTube, [EnumMember(Value = "cn_pico")] - CrytonightPico, + CryptonightPico, [EnumMember(Value = "argon_chukwa")] ArgonCHUKWA, @@ -406,6 +416,69 @@ public enum CryptonightHashType ArgonWRKZ, } +public partial class ConcealCoinTemplate : CoinTemplate +{ + [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(ConcealSubfamily.None)] + [JsonConverter(typeof(StringEnumConverter), true)] + public ConcealSubfamily Subfamily { get; set; } + + /// + /// Broader Cryptonight hash family + /// + [JsonConverter(typeof(StringEnumConverter), true)] + [JsonProperty(Order = -5)] + public CryptonightHashType Hash { get; set; } + + /// + /// Set to 0 for automatic selection from blobtemplate + /// + [JsonProperty(Order = -4, DefaultValueHandling = DefaultValueHandling.Include)] + public int HashVariant { get; set; } + + /// + /// Conceal network hashrate = `Difficulty / DifficultyTarget` + /// See: parameter -> DIFFICULTY_TARGET in src/CryptoNoteConfig.h + /// + public ulong DifficultyTarget { get; set; } + + /// + /// Smallest unit for Blockreward formatting + /// + public decimal SmallestUnit { get; set; } + + /// + /// Prefix of a valid address + /// See: parameter -> CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX in src/CryptoNoteConfig.h + /// + public ulong AddressPrefix { get; set; } + + /// + /// Prefix of a valid testnet-address + /// See: parameter -> CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX in src/CryptoNoteConfig.h + /// + public ulong AddressPrefixTestnet { get; set; } + + /// + /// Prefix of a valid integrated address + /// See: parameter -> CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX in src/CryptoNoteConfig.h + /// + public ulong AddressPrefixIntegrated { get; set; } + + /// + /// Prefix of a valid integrated testnet-address + /// See: parameter -> CRYPTONOTE_PUBLIC_ADDRESS_BASE58_PREFIX in src/CryptoNoteConfig.h + /// + public ulong AddressPrefixIntegratedTestnet { get; set; } + + /// + /// Fraction of block reward, the pool really gets to keep + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] + [DefaultValue(1.0d)] + public decimal BlockrewardMultiplier { get; set; } +} + public partial class CryptonoteCoinTemplate : CoinTemplate { [JsonProperty(Order = -7, DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] diff --git a/src/Miningcore/Configuration/ClusterConfigExtensions.cs b/src/Miningcore/Configuration/ClusterConfigExtensions.cs index 687d672f1..d7c783306 100644 --- a/src/Miningcore/Configuration/ClusterConfigExtensions.cs +++ b/src/Miningcore/Configuration/ClusterConfigExtensions.cs @@ -146,6 +146,24 @@ public override string GetAlgorithmName() #endregion } +public partial class ConcealCoinTemplate +{ + #region Overrides of CoinTemplate + + public override string GetAlgorithmName() + { +// switch(Hash) +// { +// case CryptonightHashType.RandomX: +// return "RandomX"; +// } + + return Hash.ToString(); + } + + #endregion +} + public partial class CryptonoteCoinTemplate { #region Overrides of CoinTemplate diff --git a/src/Miningcore/Crypto/Hashing/Etchash/DagEtchash.cs b/src/Miningcore/Crypto/Hashing/Etchash/DagEtchash.cs new file mode 100644 index 000000000..447c372ce --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Etchash/DagEtchash.cs @@ -0,0 +1,143 @@ +using System.Diagnostics; +using System.Text; +using Miningcore.Blockchain.Ethereum; +using Miningcore.Contracts; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Native; +using Miningcore.Notifications.Messages; +using NLog; + +namespace Miningcore.Crypto.Hashing.Etchash; + +public class DagEtchash : IDisposable +{ + public DagEtchash(ulong epoch) + { + Epoch = epoch; + } + + public ulong Epoch { get; set; } + + private IntPtr handle = IntPtr.Zero; + private static readonly Semaphore sem = new(1, 1); + + internal static IMessageBus messageBus; + + public DateTime LastUsed { get; set; } + + public static unsafe string GetDefaultDagDirectory() + { + var chars = new byte[512]; + + fixed (byte* data = chars) + { + if(EtcHash.ethash_get_default_dirname(data, chars.Length)) + { + int length; + for(length = 0; length < chars.Length; length++) + { + if(data[length] == 0) + break; + } + + return Encoding.UTF8.GetString(data, length); + } + } + + return null; + } + + public void Dispose() + { + if(handle != IntPtr.Zero) + { + EtcHash.ethash_full_delete(handle); + handle = IntPtr.Zero; + } + } + + public async Task GenerateAsync(string dagDir, ulong dagEpochLength, ILogger logger, CancellationToken ct) + { + Contract.Requires(!string.IsNullOrEmpty(dagDir)); + + if(handle == IntPtr.Zero) + { + await Task.Run(() => + { + try + { + sem.WaitOne(); + + // re-check after obtaining lock + if(handle != IntPtr.Zero) + return; + + logger.Info(() => $"Generating DAG for epoch {Epoch}"); + + var started = DateTime.Now; + var block = Epoch * dagEpochLength; + + logger.Debug(() => $"Epoch length used: {dagEpochLength}"); + + // Generate a temporary cache + var light = EtcHash.ethash_light_new(block); + + try + { + // Generate the actual DAG + handle = EtcHash.ethash_full_new(dagDir, light, progress => + { + logger.Info(() => $"Generating DAG for epoch {Epoch}: {progress}%"); + + return !ct.IsCancellationRequested ? 0 : 1; + }); + + if(handle == IntPtr.Zero) + throw new OutOfMemoryException("ethash_full_new IO or memory error"); + + logger.Info(() => $"Done generating DAG for epoch {Epoch} after {DateTime.Now - started}"); + } + + finally + { + if(light != IntPtr.Zero) + EtcHash.ethash_light_delete(light); + } + } + + finally + { + sem.Release(); + } + }, ct); + } + } + + public unsafe bool Compute(ILogger logger, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result) + { + Contract.RequiresNonNull(hash); + + var sw = Stopwatch.StartNew(); + + mixDigest = null; + result = null; + + var value = new EtcHash.ethash_return_value(); + + fixed (byte* input = hash) + { + EtcHash.ethash_full_compute(handle, input, nonce, ref value); + } + + if(value.success) + { + mixDigest = value.mix_hash.value; + result = value.result.value; + } + + messageBus?.SendTelemetry("Etchash", TelemetryCategory.Hash, sw.Elapsed, value.success); + + return value.success; + } +} diff --git a/src/Miningcore/Crypto/Hashing/Etchash/EtchashFull.cs b/src/Miningcore/Crypto/Hashing/Etchash/EtchashFull.cs new file mode 100644 index 000000000..a5edd7aa0 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Etchash/EtchashFull.cs @@ -0,0 +1,94 @@ +using Miningcore.Blockchain.Ethereum; +using Miningcore.Contracts; +using NLog; + +namespace Miningcore.Crypto.Hashing.Etchash; + +public class EtchashFull : IDisposable +{ + public EtchashFull(int numCaches, string dagDir, ulong hardForkBlock) + { + Contract.Requires(!string.IsNullOrEmpty(dagDir)); + + this.numCaches = numCaches; + this.dagDir = dagDir; + this.hardForkBlock = hardForkBlock; + } + + private int numCaches; // Maximum number of caches to keep before eviction (only init, don't modify) + private readonly object cacheLock = new(); + private readonly Dictionary caches = new(); + private DagEtchash future; + private readonly string dagDir; + private readonly ulong hardForkBlock; + + public void Dispose() + { + foreach(var value in caches.Values) + value.Dispose(); + } + + public async Task GetDagAsync(ulong block, ILogger logger, CancellationToken ct) + { + var dagEpochLength = block >= hardForkBlock ? EthereumClassicConstants.EpochLength : EthereumConstants.EpochLength; + logger.Debug(() => $"Epoch length used: {dagEpochLength}"); + var epoch = block / dagEpochLength; + DagEtchash result; + + lock(cacheLock) + { + if(numCaches == 0) + numCaches = 3; + + if(!caches.TryGetValue(epoch, out result)) + { + // No cached DAG, evict the oldest if the cache limit was reached + while(caches.Count >= numCaches) + { + var toEvict = caches.Values.OrderBy(x => x.LastUsed).First(); + var key = caches.First(pair => pair.Value == toEvict).Key; + var epochToEvict = toEvict.Epoch; + + logger.Info(() => $"Evicting DAG for epoch {epochToEvict} in favour of epoch {epoch}"); + toEvict.Dispose(); + caches.Remove(key); + } + + // If we have the new DAG pre-generated, use that, otherwise create a new one + if(future != null && future.Epoch == epoch) + { + logger.Debug(() => $"Using pre-generated DAG for epoch {epoch}"); + + result = future; + future = null; + } + + else + { + logger.Info(() => $"No pre-generated DAG available, creating new for epoch {epoch}"); + result = new DagEtchash(epoch); + } + + caches[epoch] = result; + } + + // If we used up the future cache, or need a refresh, regenerate + else if(future == null || future.Epoch <= epoch) + { + logger.Info(() => $"Pre-generating DAG for epoch {epoch + 1}"); + future = new DagEtchash(epoch + 1); + +#pragma warning disable 4014 + future.GenerateAsync(dagDir, dagEpochLength, logger, ct); +#pragma warning restore 4014 + } + + result.LastUsed = DateTime.Now; + } + + // get/generate current one + await result.GenerateAsync(dagDir, dagEpochLength, logger, ct); + + return result; + } +} diff --git a/src/Miningcore/Crypto/Hashing/Ubqhash/DagUbqhash.cs b/src/Miningcore/Crypto/Hashing/Ubqhash/DagUbqhash.cs new file mode 100644 index 000000000..9902f7cab --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Ubqhash/DagUbqhash.cs @@ -0,0 +1,141 @@ +using System.Diagnostics; +using System.Text; +using Miningcore.Blockchain.Ethereum; +using Miningcore.Contracts; +using Miningcore.Extensions; +using Miningcore.Messaging; +using Miningcore.Native; +using Miningcore.Notifications.Messages; +using NLog; + +namespace Miningcore.Crypto.Hashing.Ubqhash; + +public class DagUbqhash : IDisposable +{ + public DagUbqhash(ulong epoch) + { + Epoch = epoch; + } + + public ulong Epoch { get; set; } + + private IntPtr handle = IntPtr.Zero; + private static readonly Semaphore sem = new(1, 1); + + internal static IMessageBus messageBus; + + public DateTime LastUsed { get; set; } + + public static unsafe string GetDefaultDagDirectory() + { + var chars = new byte[512]; + + fixed (byte* data = chars) + { + if(UbqHash.ethash_get_default_dirname(data, chars.Length)) + { + int length; + for(length = 0; length < chars.Length; length++) + { + if(data[length] == 0) + break; + } + + return Encoding.UTF8.GetString(data, length); + } + } + + return null; + } + + public void Dispose() + { + if(handle != IntPtr.Zero) + { + UbqHash.ethash_full_delete(handle); + handle = IntPtr.Zero; + } + } + + public async Task GenerateAsync(string dagDir, ILogger logger, CancellationToken ct) + { + Contract.Requires(!string.IsNullOrEmpty(dagDir)); + + if(handle == IntPtr.Zero) + { + await Task.Run(() => + { + try + { + sem.WaitOne(); + + // re-check after obtaining lock + if(handle != IntPtr.Zero) + return; + + logger.Info(() => $"Generating DAG for epoch {Epoch}"); + + var started = DateTime.Now; + var block = Epoch * EthereumConstants.EpochLength; + + // Generate a temporary cache + var light = UbqHash.ethash_light_new(block); + + try + { + // Generate the actual DAG + handle = UbqHash.ethash_full_new(dagDir, light, progress => + { + logger.Info(() => $"Generating DAG for epoch {Epoch}: {progress}%"); + + return !ct.IsCancellationRequested ? 0 : 1; + }); + + if(handle == IntPtr.Zero) + throw new OutOfMemoryException("ethash_full_new IO or memory error"); + + logger.Info(() => $"Done generating DAG for epoch {Epoch} after {DateTime.Now - started}"); + } + + finally + { + if(light != IntPtr.Zero) + UbqHash.ethash_light_delete(light); + } + } + + finally + { + sem.Release(); + } + }, ct); + } + } + + public unsafe bool Compute(ILogger logger, byte[] hash, ulong nonce, out byte[] mixDigest, out byte[] result) + { + Contract.RequiresNonNull(hash); + + var sw = Stopwatch.StartNew(); + + mixDigest = null; + result = null; + + var value = new UbqHash.ethash_return_value(); + + fixed (byte* input = hash) + { + UbqHash.ethash_full_compute(handle, input, nonce, ref value); + } + + if(value.success) + { + mixDigest = value.mix_hash.value; + result = value.result.value; + } + + messageBus?.SendTelemetry("Ubqhash", TelemetryCategory.Hash, sw.Elapsed, value.success); + + return value.success; + } +} diff --git a/src/Miningcore/Crypto/Hashing/Ubqhash/UbqhashFull.cs b/src/Miningcore/Crypto/Hashing/Ubqhash/UbqhashFull.cs new file mode 100644 index 000000000..dbbb62bc3 --- /dev/null +++ b/src/Miningcore/Crypto/Hashing/Ubqhash/UbqhashFull.cs @@ -0,0 +1,90 @@ +using Miningcore.Blockchain.Ethereum; +using Miningcore.Contracts; +using NLog; + +namespace Miningcore.Crypto.Hashing.Ubqhash; + +public class UbqhashFull : IDisposable +{ + public UbqhashFull(int numCaches, string dagDir) + { + Contract.Requires(!string.IsNullOrEmpty(dagDir)); + + this.numCaches = numCaches; + this.dagDir = dagDir; + } + + private int numCaches; // Maximum number of caches to keep before eviction (only init, don't modify) + private readonly object cacheLock = new(); + private readonly Dictionary caches = new(); + private DagUbqhash future; + private readonly string dagDir; + + public void Dispose() + { + foreach(var value in caches.Values) + value.Dispose(); + } + + public async Task GetDagAsync(ulong block, ILogger logger, CancellationToken ct) + { + var epoch = block / EthereumConstants.EpochLength; + DagUbqhash result; + + lock(cacheLock) + { + if(numCaches == 0) + numCaches = 3; + + if(!caches.TryGetValue(epoch, out result)) + { + // No cached DAG, evict the oldest if the cache limit was reached + while(caches.Count >= numCaches) + { + var toEvict = caches.Values.OrderBy(x => x.LastUsed).First(); + var key = caches.First(pair => pair.Value == toEvict).Key; + var epochToEvict = toEvict.Epoch; + + logger.Info(() => $"Evicting DAG for epoch {epochToEvict} in favour of epoch {epoch}"); + toEvict.Dispose(); + caches.Remove(key); + } + + // If we have the new DAG pre-generated, use that, otherwise create a new one + if(future != null && future.Epoch == epoch) + { + logger.Debug(() => $"Using pre-generated DAG for epoch {epoch}"); + + result = future; + future = null; + } + + else + { + logger.Info(() => $"No pre-generated DAG available, creating new for epoch {epoch}"); + result = new DagUbqhash(epoch); + } + + caches[epoch] = result; + } + + // If we used up the future cache, or need a refresh, regenerate + else if(future == null || future.Epoch <= epoch) + { + logger.Info(() => $"Pre-generating DAG for epoch {epoch + 1}"); + future = new DagUbqhash(epoch + 1); + +#pragma warning disable 4014 + future.GenerateAsync(dagDir, logger, ct); +#pragma warning restore 4014 + } + + result.LastUsed = DateTime.Now; + } + + // get/generate current one + await result.GenerateAsync(dagDir, logger, ct); + + return result; + } +} diff --git a/src/Miningcore/Native/EtcHash.cs b/src/Miningcore/Native/EtcHash.cs new file mode 100644 index 000000000..3dd80fd5f --- /dev/null +++ b/src/Miningcore/Native/EtcHash.cs @@ -0,0 +1,112 @@ +using System.Runtime.InteropServices; + +// ReSharper disable InconsistentNaming + +namespace Miningcore.Native; + +public static unsafe class EtcHash +{ + [StructLayout(LayoutKind.Sequential)] + public struct ethash_h256_t + { + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U8, SizeConst = 32)] public byte[] value; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ethash_return_value + { + public ethash_h256_t result; + public ethash_h256_t mix_hash; + + [MarshalAs(UnmanagedType.U1)] public bool success; + } + + public delegate int ethash_callback_t(uint progress); + + /// + /// Allocate and initialize a new ethash_light handler + /// + /// The block number for which to create the handler + /// Newly allocated ethash_light handler or NULL + [DllImport("libetchash", EntryPoint = "ethash_light_new_export", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ethash_light_new(ulong block_number); + + /// + /// Frees a previously allocated ethash_light handler + /// + /// The light handler to free + [DllImport("libetchash", EntryPoint = "ethash_light_delete_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void ethash_light_delete(IntPtr handle); + + /// + /// Calculate the light client data + /// + /// The light client handler + /// The 32-Byte header hash to pack into the mix + /// The nonce to pack into the mix + /// an object of ethash_return_value_t holding the return values + [DllImport("libetchash", EntryPoint = "ethash_light_compute_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void ethash_light_compute(IntPtr handle, byte* header_hash, ulong nonce, ref ethash_return_value result); + + /// + /// Allocate and initialize a new ethash_full handler + /// + /// Directory where generated DAGs reside + /// The light handler containing the cache. + /// + /// A callback function with signature of @ref ethash_callback_t + /// It accepts an unsigned with which a progress of DAG calculation + /// can be displayed. If all goes well the callback should return 0. + /// If a non-zero value is returned then DAG generation will stop. + /// Be advised. A progress value of 100 means that DAG creation is + /// almost complete and that this function will soon return succesfully. + /// It does not mean that the function has already had a succesfull return. + /// + /// + [DllImport("libetchash", EntryPoint = "ethash_full_new_export", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ethash_full_new(string dagDir, IntPtr light, ethash_callback_t callback); + + /// + /// Frees a previously allocated ethash_full handler + /// + /// The full handler to free + [DllImport("libetchash", EntryPoint = "ethash_full_delete_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void ethash_full_delete(IntPtr handle); + + /// + /// Calculate the full client data + /// + /// The full client handler + /// The 32-Byte header hash to pack into the mix + /// The nonce to pack into the mix + /// an object of ethash_return_value_t holding the return values + [DllImport("libetchash", EntryPoint = "ethash_full_compute_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void ethash_full_compute(IntPtr handle, byte* header_hash, ulong nonce, ref ethash_return_value result); + + /// + /// Get a pointer to the full DAG data + /// + /// The full handler to free + [DllImport("libetchash", EntryPoint = "ethash_full_dag_export", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ethash_full_dag(IntPtr handle); + + /// + /// Get the size of the DAG data + /// + /// The full handler to free + [DllImport("libetchash", EntryPoint = "ethash_full_dag_size_export", CallingConvention = CallingConvention.Cdecl)] + public static extern ulong ethash_full_dag_size(IntPtr handle); + + /// + /// Calculate the seedhash for a given block number + /// + /// The full handler to free + [DllImport("libetchash", EntryPoint = "ethash_get_seedhash_export", CallingConvention = CallingConvention.Cdecl)] + public static extern ethash_h256_t ethash_get_seedhash(ulong block_number); + + /// + /// Get the default DAG directory + /// + [DllImport("libetchash", EntryPoint = "ethash_get_default_dirname_export", CallingConvention = CallingConvention.Cdecl)] + public static extern bool ethash_get_default_dirname(byte* data, int length); +} diff --git a/src/Miningcore/Native/UbqHash.cs b/src/Miningcore/Native/UbqHash.cs new file mode 100644 index 000000000..c4ec872a4 --- /dev/null +++ b/src/Miningcore/Native/UbqHash.cs @@ -0,0 +1,112 @@ +using System.Runtime.InteropServices; + +// ReSharper disable InconsistentNaming + +namespace Miningcore.Native; + +public static unsafe class UbqHash +{ + [StructLayout(LayoutKind.Sequential)] + public struct ethash_h256_t + { + [MarshalAs(UnmanagedType.ByValArray, ArraySubType = UnmanagedType.U8, SizeConst = 32)] public byte[] value; + } + + [StructLayout(LayoutKind.Sequential)] + public struct ethash_return_value + { + public ethash_h256_t result; + public ethash_h256_t mix_hash; + + [MarshalAs(UnmanagedType.U1)] public bool success; + } + + public delegate int ethash_callback_t(uint progress); + + /// + /// Allocate and initialize a new ethash_light handler + /// + /// The block number for which to create the handler + /// Newly allocated ethash_light handler or NULL + [DllImport("libubqhash", EntryPoint = "ethash_light_new_export", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ethash_light_new(ulong block_number); + + /// + /// Frees a previously allocated ethash_light handler + /// + /// The light handler to free + [DllImport("libubqhash", EntryPoint = "ethash_light_delete_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void ethash_light_delete(IntPtr handle); + + /// + /// Calculate the light client data + /// + /// The light client handler + /// The 32-Byte header hash to pack into the mix + /// The nonce to pack into the mix + /// an object of ethash_return_value_t holding the return values + [DllImport("libubqhash", EntryPoint = "ethash_light_compute_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void ethash_light_compute(IntPtr handle, byte* header_hash, ulong nonce, ref ethash_return_value result); + + /// + /// Allocate and initialize a new ethash_full handler + /// + /// Directory where generated DAGs reside + /// The light handler containing the cache. + /// + /// A callback function with signature of @ref ethash_callback_t + /// It accepts an unsigned with which a progress of DAG calculation + /// can be displayed. If all goes well the callback should return 0. + /// If a non-zero value is returned then DAG generation will stop. + /// Be advised. A progress value of 100 means that DAG creation is + /// almost complete and that this function will soon return succesfully. + /// It does not mean that the function has already had a succesfull return. + /// + /// + [DllImport("libubqhash", EntryPoint = "ethash_full_new_export", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ethash_full_new(string dagDir, IntPtr light, ethash_callback_t callback); + + /// + /// Frees a previously allocated ethash_full handler + /// + /// The full handler to free + [DllImport("libubqhash", EntryPoint = "ethash_full_delete_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void ethash_full_delete(IntPtr handle); + + /// + /// Calculate the full client data + /// + /// The full client handler + /// The 32-Byte header hash to pack into the mix + /// The nonce to pack into the mix + /// an object of ethash_return_value_t holding the return values + [DllImport("libubqhash", EntryPoint = "ethash_full_compute_export", CallingConvention = CallingConvention.Cdecl)] + public static extern void ethash_full_compute(IntPtr handle, byte* header_hash, ulong nonce, ref ethash_return_value result); + + /// + /// Get a pointer to the full DAG data + /// + /// The full handler to free + [DllImport("libubqhash", EntryPoint = "ethash_full_dag_export", CallingConvention = CallingConvention.Cdecl)] + public static extern IntPtr ethash_full_dag(IntPtr handle); + + /// + /// Get the size of the DAG data + /// + /// The full handler to free + [DllImport("libubqhash", EntryPoint = "ethash_full_dag_size_export", CallingConvention = CallingConvention.Cdecl)] + public static extern ulong ethash_full_dag_size(IntPtr handle); + + /// + /// Calculate the seedhash for a given block number + /// + /// The full handler to free + [DllImport("libubqhash", EntryPoint = "ethash_get_seedhash_export", CallingConvention = CallingConvention.Cdecl)] + public static extern ethash_h256_t ethash_get_seedhash(ulong block_number); + + /// + /// Get the default DAG directory + /// + [DllImport("libubqhash", EntryPoint = "ethash_get_default_dirname_export", CallingConvention = CallingConvention.Cdecl)] + public static extern bool ethash_get_default_dirname(byte* data, int length); +} diff --git a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs index beba700a1..9880f9b7f 100644 --- a/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs +++ b/src/Miningcore/Persistence/Postgres/Repositories/BlockRepository.cs @@ -113,13 +113,43 @@ public Task GetPoolBlockCountAsync(IDbConnection con, string poolId, Cance return con.ExecuteScalarAsync(query, new { poolId }); } - - public async Task GetBlockByHeightAsync(IDbConnection con, string poolId, long height) + + public async Task GetBlockByPoolHeightAndTypeAsync(IDbConnection con, string poolId, long height, string type) { - const string query = @"SELECT * FROM blocks WHERE poolid = @poolId AND blockheight = @height"; - - var entity = await con.QuerySingleOrDefaultAsync(new CommandDefinition(query, new { poolId, height })); + const string query = @"SELECT * FROM blocks WHERE poolid = @poolId AND blockheight = @height AND type = @type"; - return entity == null ? null : mapper.Map(entity); + return (await con.QueryAsync(query, new + { + poolId, + height, + type + })) + .Select(mapper.Map) + .FirstOrDefault(); + } + + public async Task GetPoolDuplicateBlockCountByPoolHeightNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, BlockStatus[] status) + { + const string query = @"SELECT COUNT(id) FROM blocks WHERE poolid = @poolId AND blockheight = @height AND status = ANY(@status)"; + + return await con.ExecuteScalarAsync(new CommandDefinition(query, new + { + poolId, + height, + status = status.Select(x => x.ToString().ToLower()).ToArray() + })); + } + + public async Task GetPoolDuplicateBlockBeforeCountByPoolHeightNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, BlockStatus[] status, DateTime before) + { + const string query = @"SELECT COUNT(id) FROM blocks WHERE poolid = @poolId AND blockheight = @height AND status = ANY(@status) AND created < @before"; + + return await con.ExecuteScalarAsync(new CommandDefinition(query, new + { + poolId, + height, + status = status.Select(x => x.ToString().ToLower()).ToArray(), + before + })); } } diff --git a/src/Miningcore/Persistence/Repositories/IBlockRepository.cs b/src/Miningcore/Persistence/Repositories/IBlockRepository.cs index 8cf1959da..3840a96c2 100644 --- a/src/Miningcore/Persistence/Repositories/IBlockRepository.cs +++ b/src/Miningcore/Persistence/Repositories/IBlockRepository.cs @@ -15,5 +15,7 @@ public interface IBlockRepository Task GetBlockBeforeAsync(IDbConnection con, string poolId, BlockStatus[] status, DateTime before); Task GetPoolBlockCountAsync(IDbConnection con, string poolId, CancellationToken ct); Task GetLastPoolBlockTimeAsync(IDbConnection con, string poolId); - Task GetBlockByHeightAsync(IDbConnection con, string poolId, long height); + Task GetBlockByPoolHeightAndTypeAsync(IDbConnection con, string poolId, long height, string type); + Task GetPoolDuplicateBlockCountByPoolHeightNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, BlockStatus[] status); + Task GetPoolDuplicateBlockBeforeCountByPoolHeightNoTypeAndStatusAsync(IDbConnection con, string poolId, long height, BlockStatus[] status, DateTime before); } diff --git a/src/Miningcore/build-libs-linux.sh b/src/Miningcore/build-libs-linux.sh index 96edf2d31..5af3bab26 100755 --- a/src/Miningcore/build-libs-linux.sh +++ b/src/Miningcore/build-libs-linux.sh @@ -23,7 +23,9 @@ HAVE_AVX512F=$(../Native/check_cpu.sh avx512f && echo -DHAVE_AVX512F || echo) export HAVE_FEATURE="$HAVE_AES $HAVE_SSE2 $HAVE_SSE3 $HAVE_SSSE3 $HAVE_AVX $HAVE_AVX2 $HAVE_AVX512F" (cd ../Native/libmultihash && make clean && make) && mv ../Native/libmultihash/libmultihash.so "$OutDir" +(cd ../Native/libetchash && make clean && make) && mv ../Native/libetchash/libetchash.so "$OutDir" (cd ../Native/libethhash && make clean && make) && mv ../Native/libethhash/libethhash.so "$OutDir" +(cd ../Native/libubqhash && make clean && make) && mv ../Native/libubqhash/libubqhash.so "$OutDir" (cd ../Native/libcryptonote && make clean && make) && mv ../Native/libcryptonote/libcryptonote.so "$OutDir" (cd ../Native/libcryptonight && make clean && make) && mv ../Native/libcryptonight/libcryptonight.so "$OutDir" diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index fa4a37586..80c1c11bd 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -4239,6 +4239,27 @@ "subAddressPrefixStagenet": 36, "explorerBlockLink": "https://www.exploremonero.com/block/$height$", "explorerTxLink": "https://www.exploremonero.com/transaction/{0}" + }, + "conceal": { + "name": "Conceal", + "canonicalName": "Conceal", + "symbol": "CCX", + "family": "conceal", + "website": "https://conceal.network/", + "market": "", + "twitter": "https://twitter.com/ConcealNetwork", + "telegram": "https://t.me/concealnetworkusers", + "discord": "http://discord.conceal.network/", + "hash": "cn-gpu", + "hashVariant": 0, + "difficultyTarget": 120, + "smallestUnit": 1000000, + "addressPrefix": 31444, + "addressPrefixTestnet": 31444, + "addressPrefixIntegrated": 31444, + "addressPrefixIntegratedTestnet": 31444, + "explorerBlockLink": "https://explorer.conceal.network/index.html?hash=$hash$#blockchain_block", + "explorerTxLink": "https://explorer.conceal.network/index.html?hash={0}#blockchain_transaction" }, "callisto": { "name": "Callisto Network", @@ -4274,6 +4295,23 @@ "explorerTxLink": "https://etherscan.io/tx/{0}", "explorerAccountLink": "https://etherscan.io/address/{0}" }, + "ethereumclassic": { + "name": "Ethereum Classic", + "canonicalName": "Ethereum Classic", + "symbol": "ETC", + "family": "ethereum", + "website": "https://ethereumclassic.org/", + "market": "", + "twitter": "https://twitter.com/eth_classic", + "telegram": "", + "discord": "https://ethereumclassic.org/discord", + "explorerBlockLinks": { + "block": "https://blockscout.com/etc/mainnet/block/$height$", + "uncle": "https://blockscout.com/etc/mainnet/block/$height$" + }, + "explorerTxLink": "https://blockscout.com/etc/mainnet/tx/{0}", + "explorerAccountLink": "https://blockscout.com/etc/mainnet/address/{0}" + }, "ethereum-pow": { "name": "EthereumPoW", "canonicalName": "EthereumPoW", @@ -4325,6 +4363,23 @@ "explorerTxLink": "https://pinkscan.org/tx/{0}", "explorerAccountLink": "https://pinkscan.org/address/{0}" }, + "ubiq": { + "name": "Ubiq", + "canonicalName": "Ubiq", + "symbol": "UBIQ", + "family": "ethereum", + "website": "https://ubiqsmart.com/", + "market": "", + "twitter": "https://twitter.com/ubiqsmart", + "telegram": "", + "discord": "https://discord.gg/ubiq", + "explorerBlockLinks": { + "block": "https://ubiqscan.io/block/$height$", + "uncle": "https://ubiqscan.io/uncle/$height$" + }, + "explorerTxLink": "https://ubiqscan.io/tx/{0}", + "explorerAccountLink": "https://ubiqscan.io/address/{0}" + }, "ergo": { "name": "Ergo", "canonicalName": "Ergo", diff --git a/src/Native/libetchash/Makefile b/src/Native/libetchash/Makefile new file mode 100644 index 000000000..58ac66d71 --- /dev/null +++ b/src/Native/libetchash/Makefile @@ -0,0 +1,16 @@ +CFLAGS += -g -Wall -c -fPIC -O2 -Wno-pointer-sign -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-discarded-qualifiers -Wno-unused-const-variable $(CPU_FLAGS) $(HAVE_FEATURE) +CXXFLAGS += -g -Wall -fPIC -fpermissive -O2 -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-sign-compare -std=c++11 $(CPU_FLAGS) $(HAVE_FEATURE) +LDFLAGS += -shared +TARGET = libetchash.so + +OBJECTS = internal.o io.o io_posix.o sha3.o exports.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +.PHONY: clean + +clean: + $(RM) $(TARGET) $(OBJECTS) diff --git a/src/Native/libetchash/compiler.h b/src/Native/libetchash/compiler.h new file mode 100644 index 000000000..40fc816d1 --- /dev/null +++ b/src/Native/libetchash/compiler.h @@ -0,0 +1,32 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: 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. + + cpp-ethereum 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. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file compiler.h + * @date 2014 + */ +#pragma once + +// Visual Studio doesn't support the inline keyword in C mode +#if defined(_MSC_VER) && !defined(__cplusplus) +#define inline __inline +#endif + +// pretend restrict is a standard keyword +#if defined(_MSC_VER) +#define restrict +#else +#define restrict __restrict__ +#endif diff --git a/src/Native/libetchash/data_sizes.h b/src/Native/libetchash/data_sizes.h new file mode 100644 index 000000000..83cc30bcb --- /dev/null +++ b/src/Native/libetchash/data_sizes.h @@ -0,0 +1,812 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software FoundationUUU,either version 3 of the LicenseUUU,or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be usefulU, + 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. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If notUUU,see . +*/ + +/** @file data_sizes.h +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +#pragma once + +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// 2048 Epochs (~20 years) worth of tabulated DAG sizes + +// Generated with the following Mathematica Code: + +// GetCacheSizes[n_] := Module[{ +// CacheSizeBytesInit = 2^24, +// CacheGrowth = 2^17, +// HashBytes = 64, +// j = 0}, +// Reap[ +// While[j < n, +// Module[{i = +// Floor[(CacheSizeBytesInit + CacheGrowth * j) / HashBytes]}, +// While[! PrimeQ[i], i--]; +// Sow[i*HashBytes]; j++]]]][[2]][[1]] + + +static const uint64_t dag_sizes[2048] = { + 1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U, + 1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U, + 1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U, + 1199568512U, 1207958912U, 1216345216U, 1224732032U, 1233124736U, + 1241513344U, 1249902464U, 1258290304U, 1266673792U, 1275067264U, + 1283453312U, 1291844992U, 1300234112U, 1308619904U, 1317010048U, + 1325397376U, 1333787776U, 1342176128U, 1350561664U, 1358954368U, + 1367339392U, 1375731584U, 1384118144U, 1392507008U, 1400897408U, + 1409284736U, 1417673344U, 1426062464U, 1434451072U, 1442839168U, + 1451229056U, 1459615616U, 1468006016U, 1476394112U, 1484782976U, + 1493171584U, 1501559168U, 1509948032U, 1518337664U, 1526726528U, + 1535114624U, 1543503488U, 1551892096U, 1560278656U, 1568669056U, + 1577056384U, 1585446272U, 1593831296U, 1602219392U, 1610610304U, + 1619000192U, 1627386752U, 1635773824U, 1644164224U, 1652555648U, + 1660943488U, 1669332608U, 1677721216U, 1686109312U, 1694497664U, + 1702886272U, 1711274624U, 1719661184U, 1728047744U, 1736434816U, + 1744829056U, 1753218944U, 1761606272U, 1769995904U, 1778382464U, + 1786772864U, 1795157888U, 1803550592U, 1811937664U, 1820327552U, + 1828711552U, 1837102976U, 1845488768U, 1853879936U, 1862269312U, + 1870656896U, 1879048064U, 1887431552U, 1895825024U, 1904212096U, + 1912601216U, 1920988544U, 1929379456U, 1937765504U, 1946156672U, + 1954543232U, 1962932096U, 1971321728U, 1979707264U, 1988093056U, + 1996487552U, 2004874624U, 2013262208U, 2021653888U, 2030039936U, + 2038430848U, 2046819968U, 2055208576U, 2063596672U, 2071981952U, + 2080373632U, 2088762752U, 2097149056U, 2105539712U, 2113928576U, + 2122315136U, 2130700672U, 2139092608U, 2147483264U, 2155872128U, + 2164257664U, 2172642176U, 2181035392U, 2189426048U, 2197814912U, + 2206203008U, 2214587264U, 2222979712U, 2231367808U, 2239758208U, + 2248145024U, 2256527744U, 2264922752U, 2273312128U, 2281701248U, + 2290086272U, 2298476672U, 2306867072U, 2315251072U, 2323639168U, + 2332032128U, 2340420224U, 2348808064U, 2357196416U, 2365580416U, + 2373966976U, 2382363008U, 2390748544U, 2399139968U, 2407530368U, + 2415918976U, 2424307328U, 2432695424U, 2441084288U, 2449472384U, + 2457861248U, 2466247808U, 2474637184U, 2483026816U, 2491414144U, + 2499803776U, 2508191872U, 2516582272U, 2524970368U, 2533359232U, + 2541743488U, 2550134144U, 2558525056U, 2566913408U, 2575301504U, + 2583686528U, 2592073856U, 2600467328U, 2608856192U, 2617240448U, + 2625631616U, 2634022016U, 2642407552U, 2650796416U, 2659188352U, + 2667574912U, 2675965312U, 2684352896U, 2692738688U, 2701130624U, + 2709518464U, 2717907328U, 2726293376U, 2734685056U, 2743073152U, + 2751462016U, 2759851648U, 2768232832U, 2776625536U, 2785017728U, + 2793401984U, 2801794432U, 2810182016U, 2818571648U, 2826959488U, + 2835349376U, 2843734144U, 2852121472U, 2860514432U, 2868900992U, + 2877286784U, 2885676928U, 2894069632U, 2902451584U, 2910843008U, + 2919234688U, 2927622784U, 2936011648U, 2944400768U, 2952789376U, + 2961177728U, 2969565568U, 2977951616U, 2986338944U, 2994731392U, + 3003120256U, 3011508352U, 3019895936U, 3028287104U, 3036675968U, + 3045063808U, 3053452928U, 3061837696U, 3070228352U, 3078615424U, + 3087003776U, 3095394944U, 3103782272U, 3112173184U, 3120562048U, + 3128944768U, 3137339264U, 3145725056U, 3154109312U, 3162505088U, + 3170893184U, 3179280256U, 3187669376U, 3196056704U, 3204445568U, + 3212836736U, 3221224064U, 3229612928U, 3238002304U, 3246391168U, + 3254778496U, 3263165824U, 3271556224U, 3279944576U, 3288332416U, + 3296719232U, 3305110912U, 3313500032U, 3321887104U, 3330273152U, + 3338658944U, 3347053184U, 3355440512U, 3363827072U, 3372220288U, + 3380608384U, 3388997504U, 3397384576U, 3405774208U, 3414163072U, + 3422551936U, 3430937984U, 3439328384U, 3447714176U, 3456104576U, + 3464493952U, 3472883584U, 3481268864U, 3489655168U, 3498048896U, + 3506434432U, 3514826368U, 3523213952U, 3531603584U, 3539987072U, + 3548380288U, 3556763264U, 3565157248U, 3573545344U, 3581934464U, + 3590324096U, 3598712704U, 3607098752U, 3615488384U, 3623877248U, + 3632265856U, 3640646528U, 3649043584U, 3657430144U, 3665821568U, + 3674207872U, 3682597504U, 3690984832U, 3699367808U, 3707764352U, + 3716152448U, 3724541056U, 3732925568U, 3741318016U, 3749706368U, + 3758091136U, 3766481536U, 3774872704U, 3783260032U, 3791650432U, + 3800036224U, 3808427648U, 3816815488U, 3825204608U, 3833592704U, + 3841981568U, 3850370432U, 3858755968U, 3867147904U, 3875536256U, + 3883920512U, 3892313728U, 3900702592U, 3909087872U, 3917478784U, + 3925868416U, 3934256512U, 3942645376U, 3951032192U, 3959422336U, + 3967809152U, 3976200064U, 3984588416U, 3992974976U, 4001363584U, + 4009751168U, 4018141312U, 4026530432U, 4034911616U, 4043308928U, + 4051695488U, 4060084352U, 4068472448U, 4076862848U, 4085249408U, + 4093640576U, 4102028416U, 4110413696U, 4118805632U, 4127194496U, + 4135583104U, 4143971968U, 4152360832U, 4160746112U, 4169135744U, + 4177525888U, 4185912704U, 4194303616U, 4202691968U, 4211076736U, + 4219463552U, 4227855488U, 4236246656U, 4244633728U, 4253022848U, + 4261412224U, 4269799808U, 4278184832U, 4286578048U, 4294962304U, + 4303349632U, 4311743104U, 4320130432U, 4328521088U, 4336909184U, + 4345295488U, 4353687424U, 4362073472U, 4370458496U, 4378852736U, + 4387238528U, 4395630208U, 4404019072U, 4412407424U, 4420790656U, + 4429182848U, 4437571456U, 4445962112U, 4454344064U, 4462738048U, + 4471119232U, 4479516544U, 4487904128U, 4496289664U, 4504682368U, + 4513068416U, 4521459584U, 4529846144U, 4538232704U, 4546619776U, + 4555010176U, 4563402112U, 4571790208U, 4580174464U, 4588567936U, + 4596957056U, 4605344896U, 4613734016U, 4622119808U, 4630511488U, + 4638898816U, 4647287936U, 4655675264U, 4664065664U, 4672451968U, + 4680842624U, 4689231488U, 4697620352U, 4706007424U, 4714397056U, + 4722786176U, 4731173248U, 4739562368U, 4747951744U, 4756340608U, + 4764727936U, 4773114496U, 4781504384U, 4789894784U, 4798283648U, + 4806667648U, 4815059584U, 4823449472U, 4831835776U, 4840226176U, + 4848612224U, 4857003392U, 4865391488U, 4873780096U, 4882169728U, + 4890557312U, 4898946944U, 4907333248U, 4915722368U, 4924110976U, + 4932499328U, 4940889728U, 4949276032U, 4957666432U, 4966054784U, + 4974438016U, 4982831488U, 4991221376U, 4999607168U, 5007998848U, + 5016386432U, 5024763776U, 5033164672U, 5041544576U, 5049941888U, + 5058329728U, 5066717056U, 5075107456U, 5083494272U, 5091883904U, + 5100273536U, 5108662144U, 5117048192U, 5125436032U, 5133827456U, + 5142215296U, 5150605184U, 5158993024U, 5167382144U, 5175769472U, + 5184157568U, 5192543872U, 5200936064U, 5209324928U, 5217711232U, + 5226102656U, 5234490496U, 5242877312U, 5251263872U, 5259654016U, + 5268040832U, 5276434304U, 5284819328U, 5293209728U, 5301598592U, + 5309986688U, 5318374784U, 5326764416U, 5335151488U, 5343542144U, + 5351929472U, 5360319872U, 5368706944U, 5377096576U, 5385484928U, + 5393871232U, 5402263424U, 5410650496U, 5419040384U, 5427426944U, + 5435816576U, 5444205952U, 5452594816U, 5460981376U, 5469367936U, + 5477760896U, 5486148736U, 5494536832U, 5502925952U, 5511315328U, + 5519703424U, 5528089984U, 5536481152U, 5544869504U, 5553256064U, + 5561645696U, 5570032768U, 5578423936U, 5586811264U, 5595193216U, + 5603585408U, 5611972736U, 5620366208U, 5628750464U, 5637143936U, + 5645528192U, 5653921408U, 5662310272U, 5670694784U, 5679082624U, + 5687474048U, 5695864448U, 5704251008U, 5712641408U, 5721030272U, + 5729416832U, 5737806208U, 5746194304U, 5754583936U, 5762969984U, + 5771358592U, 5779748224U, 5788137856U, 5796527488U, 5804911232U, + 5813300608U, 5821692544U, 5830082176U, 5838468992U, 5846855552U, + 5855247488U, 5863636096U, 5872024448U, 5880411008U, 5888799872U, + 5897186432U, 5905576832U, 5913966976U, 5922352768U, 5930744704U, + 5939132288U, 5947522432U, 5955911296U, 5964299392U, 5972688256U, + 5981074304U, 5989465472U, 5997851008U, 6006241408U, 6014627968U, + 6023015552U, 6031408256U, 6039796096U, 6048185216U, 6056574848U, + 6064963456U, 6073351808U, 6081736064U, 6090128768U, 6098517632U, + 6106906496U, 6115289216U, 6123680896U, 6132070016U, 6140459648U, + 6148849024U, 6157237376U, 6165624704U, 6174009728U, 6182403712U, + 6190792064U, 6199176064U, 6207569792U, 6215952256U, 6224345216U, + 6232732544U, 6241124224U, 6249510272U, 6257899136U, 6266287744U, + 6274676864U, 6283065728U, 6291454336U, 6299843456U, 6308232064U, + 6316620928U, 6325006208U, 6333395584U, 6341784704U, 6350174848U, + 6358562176U, 6366951296U, 6375337856U, 6383729536U, 6392119168U, + 6400504192U, 6408895616U, 6417283456U, 6425673344U, 6434059136U, + 6442444672U, 6450837376U, 6459223424U, 6467613056U, 6476004224U, + 6484393088U, 6492781952U, 6501170048U, 6509555072U, 6517947008U, + 6526336384U, 6534725504U, 6543112832U, 6551500672U, 6559888768U, + 6568278656U, 6576662912U, 6585055616U, 6593443456U, 6601834112U, + 6610219648U, 6618610304U, 6626999168U, 6635385472U, 6643777408U, + 6652164224U, 6660552832U, 6668941952U, 6677330048U, 6685719424U, + 6694107776U, 6702493568U, 6710882176U, 6719274112U, 6727662976U, + 6736052096U, 6744437632U, 6752825984U, 6761213824U, 6769604224U, + 6777993856U, 6786383488U, 6794770816U, 6803158144U, 6811549312U, + 6819937664U, 6828326528U, 6836706176U, 6845101696U, 6853491328U, + 6861880448U, 6870269312U, 6878655104U, 6887046272U, 6895433344U, + 6903822208U, 6912212864U, 6920596864U, 6928988288U, 6937377152U, + 6945764992U, 6954149248U, 6962544256U, 6970928768U, 6979317376U, + 6987709312U, 6996093824U, 7004487296U, 7012875392U, 7021258624U, + 7029652352U, 7038038912U, 7046427776U, 7054818944U, 7063207808U, + 7071595136U, 7079980928U, 7088372608U, 7096759424U, 7105149824U, + 7113536896U, 7121928064U, 7130315392U, 7138699648U, 7147092352U, + 7155479168U, 7163865728U, 7172249984U, 7180648064U, 7189036672U, + 7197424768U, 7205810816U, 7214196608U, 7222589824U, 7230975104U, + 7239367552U, 7247755904U, 7256145536U, 7264533376U, 7272921472U, + 7281308032U, 7289694848U, 7298088832U, 7306471808U, 7314864512U, + 7323253888U, 7331643008U, 7340029568U, 7348419712U, 7356808832U, + 7365196672U, 7373585792U, 7381973888U, 7390362752U, 7398750592U, + 7407138944U, 7415528576U, 7423915648U, 7432302208U, 7440690304U, + 7449080192U, 7457472128U, 7465860992U, 7474249088U, 7482635648U, + 7491023744U, 7499412608U, 7507803008U, 7516192384U, 7524579968U, + 7532967296U, 7541358464U, 7549745792U, 7558134656U, 7566524032U, + 7574912896U, 7583300992U, 7591690112U, 7600075136U, 7608466816U, + 7616854912U, 7625244544U, 7633629824U, 7642020992U, 7650410368U, + 7658794112U, 7667187328U, 7675574912U, 7683961984U, 7692349568U, + 7700739712U, 7709130368U, 7717519232U, 7725905536U, 7734295424U, + 7742683264U, 7751069056U, 7759457408U, 7767849088U, 7776238208U, + 7784626816U, 7793014912U, 7801405312U, 7809792128U, 7818179968U, + 7826571136U, 7834957184U, 7843347328U, 7851732352U, 7860124544U, + 7868512384U, 7876902016U, 7885287808U, 7893679744U, 7902067072U, + 7910455936U, 7918844288U, 7927230848U, 7935622784U, 7944009344U, + 7952400256U, 7960786048U, 7969176704U, 7977565312U, 7985953408U, + 7994339968U, 8002730368U, 8011119488U, 8019508096U, 8027896192U, + 8036285056U, 8044674688U, 8053062272U, 8061448832U, 8069838464U, + 8078227328U, 8086616704U, 8095006592U, 8103393664U, 8111783552U, + 8120171392U, 8128560256U, 8136949376U, 8145336704U, 8153726848U, + 8162114944U, 8170503296U, 8178891904U, 8187280768U, 8195669632U, + 8204058496U, 8212444544U, 8220834176U, 8229222272U, 8237612672U, + 8246000768U, 8254389376U, 8262775168U, 8271167104U, 8279553664U, + 8287944064U, 8296333184U, 8304715136U, 8313108352U, 8321497984U, + 8329885568U, 8338274432U, 8346663296U, 8355052928U, 8363441536U, + 8371828352U, 8380217984U, 8388606592U, 8396996224U, 8405384576U, + 8413772672U, 8422161536U, 8430549376U, 8438939008U, 8447326592U, + 8455715456U, 8464104832U, 8472492928U, 8480882048U, 8489270656U, + 8497659776U, 8506045312U, 8514434944U, 8522823808U, 8531208832U, + 8539602304U, 8547990656U, 8556378752U, 8564768384U, 8573154176U, + 8581542784U, 8589933952U, 8598322816U, 8606705024U, 8615099264U, + 8623487872U, 8631876992U, 8640264064U, 8648653952U, 8657040256U, + 8665430656U, 8673820544U, 8682209152U, 8690592128U, 8698977152U, + 8707374464U, 8715763328U, 8724151424U, 8732540032U, 8740928384U, + 8749315712U, 8757704576U, 8766089344U, 8774480768U, 8782871936U, + 8791260032U, 8799645824U, 8808034432U, 8816426368U, 8824812928U, + 8833199488U, 8841591424U, 8849976448U, 8858366336U, 8866757248U, + 8875147136U, 8883532928U, 8891923328U, 8900306816U, 8908700288U, + 8917088384U, 8925478784U, 8933867392U, 8942250368U, 8950644608U, + 8959032704U, 8967420544U, 8975809664U, 8984197504U, 8992584064U, + 9000976256U, 9009362048U, 9017752448U, 9026141312U, 9034530688U, + 9042917504U, 9051307904U, 9059694208U, 9068084864U, 9076471424U, + 9084861824U, 9093250688U, 9101638528U, 9110027648U, 9118416512U, + 9126803584U, 9135188096U, 9143581312U, 9151969664U, 9160356224U, + 9168747136U, 9177134464U, 9185525632U, 9193910144U, 9202302848U, + 9210690688U, 9219079552U, 9227465344U, 9235854464U, 9244244864U, + 9252633472U, 9261021824U, 9269411456U, 9277799296U, 9286188928U, + 9294574208U, 9302965888U, 9311351936U, 9319740032U, 9328131968U, + 9336516736U, 9344907392U, 9353296768U, 9361685888U, 9370074752U, + 9378463616U, 9386849408U, 9395239808U, 9403629184U, 9412016512U, + 9420405376U, 9428795008U, 9437181568U, 9445570688U, 9453960832U, + 9462346624U, 9470738048U, 9479121536U, 9487515008U, 9495903616U, + 9504289664U, 9512678528U, 9521067904U, 9529456256U, 9537843584U, + 9546233728U, 9554621312U, 9563011456U, 9571398784U, 9579788672U, + 9588178304U, 9596567168U, 9604954496U, 9613343104U, 9621732992U, + 9630121856U, 9638508416U, 9646898816U, 9655283584U, 9663675776U, + 9672061312U, 9680449664U, 9688840064U, 9697230464U, 9705617536U, + 9714003584U, 9722393984U, 9730772608U, 9739172224U, 9747561088U, + 9755945344U, 9764338816U, 9772726144U, 9781116544U, 9789503872U, + 9797892992U, 9806282624U, 9814670464U, 9823056512U, 9831439232U, + 9839833984U, 9848224384U, 9856613504U, 9865000576U, 9873391232U, + 9881772416U, 9890162816U, 9898556288U, 9906940544U, 9915333248U, + 9923721088U, 9932108672U, 9940496512U, 9948888448U, 9957276544U, + 9965666176U, 9974048384U, 9982441088U, 9990830464U, 9999219584U, + 10007602816U, 10015996544U, 10024385152U, 10032774016U, 10041163648U, + 10049548928U, 10057940096U, 10066329472U, 10074717824U, 10083105152U, + 10091495296U, 10099878784U, 10108272256U, 10116660608U, 10125049216U, + 10133437312U, 10141825664U, 10150213504U, 10158601088U, 10166991232U, + 10175378816U, 10183766144U, 10192157312U, 10200545408U, 10208935552U, + 10217322112U, 10225712768U, 10234099328U, 10242489472U, 10250876032U, + 10259264896U, 10267656064U, 10276042624U, 10284429184U, 10292820352U, + 10301209472U, 10309598848U, 10317987712U, 10326375296U, 10334763392U, + 10343153536U, 10351541632U, 10359930752U, 10368318592U, 10376707456U, + 10385096576U, 10393484672U, 10401867136U, 10410262144U, 10418647424U, + 10427039104U, 10435425664U, 10443810176U, 10452203648U, 10460589952U, + 10468982144U, 10477369472U, 10485759104U, 10494147712U, 10502533504U, + 10510923392U, 10519313536U, 10527702656U, 10536091264U, 10544478592U, + 10552867712U, 10561255808U, 10569642368U, 10578032768U, 10586423168U, + 10594805632U, 10603200128U, 10611588992U, 10619976064U, 10628361344U, + 10636754048U, 10645143424U, 10653531776U, 10661920384U, 10670307968U, + 10678696832U, 10687086464U, 10695475072U, 10703863168U, 10712246144U, + 10720639616U, 10729026688U, 10737414784U, 10745806208U, 10754190976U, + 10762581376U, 10770971264U, 10779356288U, 10787747456U, 10796135552U, + 10804525184U, 10812915584U, 10821301888U, 10829692288U, 10838078336U, + 10846469248U, 10854858368U, 10863247232U, 10871631488U, 10880023424U, + 10888412032U, 10896799616U, 10905188992U, 10913574016U, 10921964672U, + 10930352768U, 10938742912U, 10947132544U, 10955518592U, 10963909504U, + 10972298368U, 10980687488U, 10989074816U, 10997462912U, 11005851776U, + 11014241152U, 11022627712U, 11031017344U, 11039403904U, 11047793024U, + 11056184704U, 11064570752U, 11072960896U, 11081343872U, 11089737856U, + 11098128256U, 11106514816U, 11114904448U, 11123293568U, 11131680128U, + 11140065152U, 11148458368U, 11156845696U, 11165236864U, 11173624192U, + 11182013824U, 11190402688U, 11198790784U, 11207179136U, 11215568768U, + 11223957376U, 11232345728U, 11240734592U, 11249122688U, 11257511296U, + 11265899648U, 11274285952U, 11282675584U, 11291065472U, 11299452544U, + 11307842432U, 11316231296U, 11324616832U, 11333009024U, 11341395584U, + 11349782656U, 11358172288U, 11366560384U, 11374950016U, 11383339648U, + 11391721856U, 11400117376U, 11408504192U, 11416893568U, 11425283456U, + 11433671552U, 11442061184U, 11450444672U, 11458837888U, 11467226752U, + 11475611776U, 11484003968U, 11492392064U, 11500780672U, 11509169024U, + 11517550976U, 11525944448U, 11534335616U, 11542724224U, 11551111808U, + 11559500672U, 11567890304U, 11576277376U, 11584667008U, 11593056128U, + 11601443456U, 11609830016U, 11618221952U, 11626607488U, 11634995072U, + 11643387776U, 11651775104U, 11660161664U, 11668552576U, 11676940928U, + 11685330304U, 11693718656U, 11702106496U, 11710496128U, 11718882688U, + 11727273088U, 11735660416U, 11744050048U, 11752437376U, 11760824704U, + 11769216128U, 11777604736U, 11785991296U, 11794381952U, 11802770048U, + 11811157888U, 11819548544U, 11827932544U, 11836324736U, 11844713344U, + 11853100928U, 11861486464U, 11869879936U, 11878268032U, 11886656896U, + 11895044992U, 11903433088U, 11911822976U, 11920210816U, 11928600448U, + 11936987264U, 11945375872U, 11953761152U, 11962151296U, 11970543488U, + 11978928512U, 11987320448U, 11995708288U, 12004095104U, 12012486272U, + 12020875136U, 12029255552U, 12037652096U, 12046039168U, 12054429568U, + 12062813824U, 12071206528U, 12079594624U, 12087983744U, 12096371072U, + 12104759936U, 12113147264U, 12121534592U, 12129924992U, 12138314624U, + 12146703232U, 12155091584U, 12163481216U, 12171864704U, 12180255872U, + 12188643968U, 12197034112U, 12205424512U, 12213811328U, 12222199424U, + 12230590336U, 12238977664U, 12247365248U, 12255755392U, 12264143488U, + 12272531584U, 12280920448U, 12289309568U, 12297694592U, 12306086528U, + 12314475392U, 12322865024U, 12331253632U, 12339640448U, 12348029312U, + 12356418944U, 12364805248U, 12373196672U, 12381580928U, 12389969024U, + 12398357632U, 12406750592U, 12415138432U, 12423527552U, 12431916416U, + 12440304512U, 12448692352U, 12457081216U, 12465467776U, 12473859968U, + 12482245504U, 12490636672U, 12499025536U, 12507411584U, 12515801728U, + 12524190592U, 12532577152U, 12540966272U, 12549354368U, 12557743232U, + 12566129536U, 12574523264U, 12582911872U, 12591299456U, 12599688064U, + 12608074624U, 12616463488U, 12624845696U, 12633239936U, 12641631616U, + 12650019968U, 12658407296U, 12666795136U, 12675183232U, 12683574656U, + 12691960192U, 12700350592U, 12708740224U, 12717128576U, 12725515904U, + 12733906816U, 12742295168U, 12750680192U, 12759071872U, 12767460736U, + 12775848832U, 12784236928U, 12792626816U, 12801014656U, 12809404288U, + 12817789312U, 12826181504U, 12834568832U, 12842954624U, 12851345792U, + 12859732352U, 12868122496U, 12876512128U, 12884901248U, 12893289088U, + 12901672832U, 12910067584U, 12918455168U, 12926842496U, 12935232896U, + 12943620736U, 12952009856U, 12960396928U, 12968786816U, 12977176192U, + 12985563776U, 12993951104U, 13002341504U, 13010730368U, 13019115392U, + 13027506304U, 13035895168U, 13044272512U, 13052673152U, 13061062528U, + 13069446272U, 13077838976U, 13086227072U, 13094613632U, 13103000192U, + 13111393664U, 13119782528U, 13128157568U, 13136559232U, 13144945024U, + 13153329536U, 13161724288U, 13170111872U, 13178502784U, 13186884736U, + 13195279744U, 13203667072U, 13212057472U, 13220445824U, 13228832128U, + 13237221248U, 13245610624U, 13254000512U, 13262388352U, 13270777472U, + 13279166336U, 13287553408U, 13295943296U, 13304331904U, 13312719488U, + 13321108096U, 13329494656U, 13337885824U, 13346274944U, 13354663808U, + 13363051136U, 13371439232U, 13379825024U, 13388210816U, 13396605056U, + 13404995456U, 13413380224U, 13421771392U, 13430159744U, 13438546048U, + 13446937216U, 13455326848U, 13463708288U, 13472103808U, 13480492672U, + 13488875648U, 13497269888U, 13505657728U, 13514045312U, 13522435712U, + 13530824576U, 13539210112U, 13547599232U, 13555989376U, 13564379008U, + 13572766336U, 13581154432U, 13589544832U, 13597932928U, 13606320512U, + 13614710656U, 13623097472U, 13631477632U, 13639874944U, 13648264064U, + 13656652928U, 13665041792U, 13673430656U, 13681818496U, 13690207616U, + 13698595712U, 13706982272U, 13715373184U, 13723762048U, 13732150144U, + 13740536704U, 13748926592U, 13757316224U, 13765700992U, 13774090112U, + 13782477952U, 13790869376U, 13799259008U, 13807647872U, 13816036736U, + 13824425344U, 13832814208U, 13841202304U, 13849591424U, 13857978752U, + 13866368896U, 13874754688U, 13883145344U, 13891533184U, 13899919232U, + 13908311168U, 13916692096U, 13925085056U, 13933473152U, 13941866368U, + 13950253696U, 13958643584U, 13967032192U, 13975417216U, 13983807616U, + 13992197504U, 14000582272U, 14008973696U, 14017363072U, 14025752192U, + 14034137984U, 14042528384U, 14050918016U, 14059301504U, 14067691648U, + 14076083584U, 14084470144U, 14092852352U, 14101249664U, 14109635968U, + 14118024832U, 14126407552U, 14134804352U, 14143188608U, 14151577984U, + 14159968384U, 14168357248U, 14176741504U, 14185127296U, 14193521024U, + 14201911424U, 14210301824U, 14218685056U, 14227067264U, 14235467392U, + 14243855488U, 14252243072U, 14260630144U, 14269021568U, 14277409408U, + 14285799296U, 14294187904U, 14302571392U, 14310961792U, 14319353728U, + 14327738752U, 14336130944U, 14344518784U, 14352906368U, 14361296512U, + 14369685376U, 14378071424U, 14386462592U, 14394848128U, 14403230848U, + 14411627392U, 14420013952U, 14428402304U, 14436793472U, 14445181568U, + 14453569664U, 14461959808U, 14470347904U, 14478737024U, 14487122816U, + 14495511424U, 14503901824U, 14512291712U, 14520677504U, 14529064832U, + 14537456768U, 14545845632U, 14554234496U, 14562618496U, 14571011456U, + 14579398784U, 14587789184U, 14596172672U, 14604564608U, 14612953984U, + 14621341312U, 14629724288U, 14638120832U, 14646503296U, 14654897536U, + 14663284864U, 14671675264U, 14680061056U, 14688447616U, 14696835968U, + 14705228416U, 14713616768U, 14722003328U, 14730392192U, 14738784128U, + 14747172736U, 14755561088U, 14763947648U, 14772336512U, 14780725376U, + 14789110144U, 14797499776U, 14805892736U, 14814276992U, 14822670208U, + 14831056256U, 14839444352U, 14847836032U, 14856222848U, 14864612992U, + 14872997504U, 14881388672U, 14889775744U, 14898165376U, 14906553472U, + 14914944896U, 14923329664U, 14931721856U, 14940109696U, 14948497024U, + 14956887424U, 14965276544U, 14973663616U, 14982053248U, 14990439808U, + 14998830976U, 15007216768U, 15015605888U, 15023995264U, 15032385152U, + 15040768384U, 15049154944U, 15057549184U, 15065939072U, 15074328448U, + 15082715008U, 15091104128U, 15099493504U, 15107879296U, 15116269184U, + 15124659584U, 15133042304U, 15141431936U, 15149824384U, 15158214272U, + 15166602368U, 15174991232U, 15183378304U, 15191760512U, 15200154496U, + 15208542592U, 15216931712U, 15225323392U, 15233708416U, 15242098048U, + 15250489216U, 15258875264U, 15267265408U, 15275654528U, 15284043136U, + 15292431488U, 15300819584U, 15309208192U, 15317596544U, 15325986176U, + 15334374784U, 15342763648U, 15351151744U, 15359540608U, 15367929728U, + 15376318336U, 15384706432U, 15393092992U, 15401481856U, 15409869952U, + 15418258816U, 15426649984U, 15435037568U, 15443425664U, 15451815296U, + 15460203392U, 15468589184U, 15476979328U, 15485369216U, 15493755776U, + 15502146944U, 15510534272U, 15518924416U, 15527311232U, 15535699072U, + 15544089472U, 15552478336U, 15560866688U, 15569254528U, 15577642624U, + 15586031488U, 15594419072U, 15602809472U, 15611199104U, 15619586432U, + 15627975296U, 15636364928U, 15644753792U, 15653141888U, 15661529216U, + 15669918848U, 15678305152U, 15686696576U, 15695083136U, 15703474048U, + 15711861632U, 15720251264U, 15728636288U, 15737027456U, 15745417088U, + 15753804928U, 15762194048U, 15770582656U, 15778971008U, 15787358336U, + 15795747712U, 15804132224U, 15812523392U, 15820909696U, 15829300096U, + 15837691264U, 15846071936U, 15854466944U, 15862855808U, 15871244672U, + 15879634816U, 15888020608U, 15896409728U, 15904799104U, 15913185152U, + 15921577088U, 15929966464U, 15938354816U, 15946743424U, 15955129472U, + 15963519872U, 15971907968U, 15980296064U, 15988684928U, 15997073024U, + 16005460864U, 16013851264U, 16022241152U, 16030629248U, 16039012736U, + 16047406976U, 16055794816U, 16064181376U, 16072571264U, 16080957824U, + 16089346688U, 16097737856U, 16106125184U, 16114514816U, 16122904192U, + 16131292544U, 16139678848U, 16148066944U, 16156453504U, 16164839552U, + 16173236096U, 16181623424U, 16190012032U, 16198401152U, 16206790528U, + 16215177344U, 16223567744U, 16231956352U, 16240344704U, 16248731008U, + 16257117824U, 16265504384U, 16273898624U, 16282281856U, 16290668672U, + 16299064192U, 16307449216U, 16315842176U, 16324230016U, 16332613504U, + 16341006464U, 16349394304U, 16357783168U, 16366172288U, 16374561664U, + 16382951296U, 16391337856U, 16399726208U, 16408116352U, 16416505472U, + 16424892032U, 16433282176U, 16441668224U, 16450058624U, 16458448768U, + 16466836864U, 16475224448U, 16483613056U, 16492001408U, 16500391808U, + 16508779648U, 16517166976U, 16525555328U, 16533944192U, 16542330752U, + 16550719616U, 16559110528U, 16567497088U, 16575888512U, 16584274816U, + 16592665472U, 16601051008U, 16609442944U, 16617832064U, 16626218624U, + 16634607488U, 16642996096U, 16651385728U, 16659773824U, 16668163712U, + 16676552576U, 16684938112U, 16693328768U, 16701718144U, 16710095488U, + 16718492288U, 16726883968U, 16735272832U, 16743661184U, 16752049792U, + 16760436608U, 16768827008U, 16777214336U, 16785599104U, 16793992832U, + 16802381696U, 16810768768U, 16819151744U, 16827542656U, 16835934848U, + 16844323712U, 16852711552U, 16861101952U, 16869489536U, 16877876864U, + 16886265728U, 16894653056U, 16903044736U, 16911431296U, 16919821696U, + 16928207488U, 16936592768U, 16944987776U, 16953375616U, 16961763968U, + 16970152832U, 16978540928U, 16986929536U, 16995319168U, 17003704448U, + 17012096896U, 17020481152U, 17028870784U, 17037262208U, 17045649536U, + 17054039936U, 17062426496U, 17070814336U, 17079205504U, 17087592064U, + 17095978112U, 17104369024U, 17112759424U, 17121147776U, 17129536384U, + 17137926016U, 17146314368U, 17154700928U, 17163089792U, 17171480192U, + 17179864192U, 17188256896U, 17196644992U, 17205033856U, 17213423488U, + 17221811072U, 17230198912U, 17238588032U, 17246976896U, 17255360384U, + 17263754624U, 17272143232U, 17280530048U, 17288918912U, 17297309312U, + 17305696384U, 17314085504U, 17322475136U, 17330863744U, 17339252096U, + 17347640192U, 17356026496U, 17364413824U, 17372796544U, 17381190016U, + 17389583488U, 17397972608U, 17406360704U, 17414748544U, 17423135872U, + 17431527296U, 17439915904U, 17448303232U, 17456691584U, 17465081728U, + 17473468288U, 17481857408U, 17490247552U, 17498635904U, 17507022464U, + 17515409024U, 17523801728U, 17532189824U, 17540577664U, 17548966016U, + 17557353344U, 17565741184U, 17574131584U, 17582519168U, 17590907008U, + 17599296128U, 17607687808U, 17616076672U, 17624455808U, 17632852352U, + 17641238656U, 17649630848U, 17658018944U, 17666403968U, 17674794112U, + 17683178368U, 17691573376U, 17699962496U, 17708350592U, 17716739968U, + 17725126528U, 17733517184U, 17741898112U, 17750293888U, 17758673024U, + 17767070336U, 17775458432U, 17783848832U, 17792236928U, 17800625536U, + 17809012352U, 17817402752U, 17825785984U, 17834178944U, 17842563968U, + 17850955648U, 17859344512U, 17867732864U, 17876119424U, 17884511872U, + 17892900224U, 17901287296U, 17909677696U, 17918058112U, 17926451072U, + 17934843776U, 17943230848U, 17951609216U, 17960008576U, 17968397696U, + 17976784256U, 17985175424U, 17993564032U, 18001952128U, 18010339712U, + 18018728576U, 18027116672U, 18035503232U, 18043894144U, 18052283264U, + 18060672128U, 18069056384U, 18077449856U, 18085837184U, 18094225792U, + 18102613376U, 18111004544U, 18119388544U, 18127781248U, 18136170368U, + 18144558976U, 18152947328U, 18161336192U, 18169724288U, 18178108544U, + 18186498944U, 18194886784U, 18203275648U, 18211666048U, 18220048768U, + 18228444544U, 18236833408U, 18245220736U +}; + + +// Generated with the following Mathematica Code: + +// GetCacheSizes[n_] := Module[{ +// DataSetSizeBytesInit = 2^30, +// MixBytes = 128, +// DataSetGrowth = 2^23, +// HashBytes = 64, +// CacheMultiplier = 1024, +// j = 0}, +// Reap[ +// While[j < n, +// Module[{i = Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / (CacheMultiplier * HashBytes)]}, +// While[! PrimeQ[i], i--]; +// Sow[i*HashBytes]; j++]]]][[2]][[1]] + +const uint64_t cache_sizes[2048] = { + 16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U, + 17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U, + 18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U, + 19529408U, 19660096U, 19791424U, 19922752U, 20053952U, 20184896U, 20315968U, + 20446912U, 20576576U, 20709184U, 20840384U, 20971072U, 21102272U, 21233216U, + 21364544U, 21494848U, 21626816U, 21757376U, 21887552U, 22019392U, 22151104U, + 22281536U, 22412224U, 22543936U, 22675264U, 22806464U, 22935872U, 23068096U, + 23198272U, 23330752U, 23459008U, 23592512U, 23723968U, 23854912U, 23986112U, + 24116672U, 24247616U, 24378688U, 24509504U, 24640832U, 24772544U, 24903488U, + 25034432U, 25165376U, 25296704U, 25427392U, 25558592U, 25690048U, 25820096U, + 25951936U, 26081728U, 26214208U, 26345024U, 26476096U, 26606656U, 26737472U, + 26869184U, 26998208U, 27131584U, 27262528U, 27393728U, 27523904U, 27655744U, + 27786688U, 27917888U, 28049344U, 28179904U, 28311488U, 28441792U, 28573504U, + 28700864U, 28835648U, 28966208U, 29096768U, 29228608U, 29359808U, 29490752U, + 29621824U, 29752256U, 29882816U, 30014912U, 30144448U, 30273728U, 30406976U, + 30538432U, 30670784U, 30799936U, 30932672U, 31063744U, 31195072U, 31325248U, + 31456192U, 31588288U, 31719232U, 31850432U, 31981504U, 32110784U, 32243392U, + 32372672U, 32505664U, 32636608U, 32767808U, 32897344U, 33029824U, 33160768U, + 33289664U, 33423296U, 33554368U, 33683648U, 33816512U, 33947456U, 34076992U, + 34208704U, 34340032U, 34471744U, 34600256U, 34734016U, 34864576U, 34993984U, + 35127104U, 35258176U, 35386688U, 35518528U, 35650624U, 35782336U, 35910976U, + 36044608U, 36175808U, 36305728U, 36436672U, 36568384U, 36699968U, 36830656U, + 36961984U, 37093312U, 37223488U, 37355072U, 37486528U, 37617472U, 37747904U, + 37879232U, 38009792U, 38141888U, 38272448U, 38403392U, 38535104U, 38660672U, + 38795584U, 38925632U, 39059264U, 39190336U, 39320768U, 39452096U, 39581632U, + 39713984U, 39844928U, 39974848U, 40107968U, 40238144U, 40367168U, 40500032U, + 40631744U, 40762816U, 40894144U, 41023552U, 41155904U, 41286208U, 41418304U, + 41547712U, 41680448U, 41811904U, 41942848U, 42073792U, 42204992U, 42334912U, + 42467008U, 42597824U, 42729152U, 42860096U, 42991552U, 43122368U, 43253696U, + 43382848U, 43515712U, 43646912U, 43777088U, 43907648U, 44039104U, 44170432U, + 44302144U, 44433344U, 44564288U, 44694976U, 44825152U, 44956864U, 45088448U, + 45219008U, 45350464U, 45481024U, 45612608U, 45744064U, 45874496U, 46006208U, + 46136768U, 46267712U, 46399424U, 46529344U, 46660672U, 46791488U, 46923328U, + 47053504U, 47185856U, 47316928U, 47447872U, 47579072U, 47710144U, 47839936U, + 47971648U, 48103232U, 48234176U, 48365248U, 48496192U, 48627136U, 48757312U, + 48889664U, 49020736U, 49149248U, 49283008U, 49413824U, 49545152U, 49675712U, + 49807168U, 49938368U, 50069056U, 50200256U, 50331584U, 50462656U, 50593472U, + 50724032U, 50853952U, 50986048U, 51117632U, 51248576U, 51379904U, 51510848U, + 51641792U, 51773248U, 51903296U, 52035136U, 52164032U, 52297664U, 52427968U, + 52557376U, 52690112U, 52821952U, 52952896U, 53081536U, 53213504U, 53344576U, + 53475776U, 53608384U, 53738816U, 53870528U, 54000832U, 54131776U, 54263744U, + 54394688U, 54525248U, 54655936U, 54787904U, 54918592U, 55049152U, 55181248U, + 55312064U, 55442752U, 55574336U, 55705024U, 55836224U, 55967168U, 56097856U, + 56228672U, 56358592U, 56490176U, 56621888U, 56753728U, 56884928U, 57015488U, + 57146816U, 57278272U, 57409216U, 57540416U, 57671104U, 57802432U, 57933632U, + 58064576U, 58195264U, 58326976U, 58457408U, 58588864U, 58720192U, 58849984U, + 58981696U, 59113024U, 59243456U, 59375552U, 59506624U, 59637568U, 59768512U, + 59897792U, 60030016U, 60161984U, 60293056U, 60423872U, 60554432U, 60683968U, + 60817216U, 60948032U, 61079488U, 61209664U, 61341376U, 61471936U, 61602752U, + 61733696U, 61865792U, 61996736U, 62127808U, 62259136U, 62389568U, 62520512U, + 62651584U, 62781632U, 62910784U, 63045056U, 63176128U, 63307072U, 63438656U, + 63569216U, 63700928U, 63831616U, 63960896U, 64093888U, 64225088U, 64355392U, + 64486976U, 64617664U, 64748608U, 64879424U, 65009216U, 65142464U, 65273792U, + 65402816U, 65535424U, 65666752U, 65797696U, 65927744U, 66060224U, 66191296U, + 66321344U, 66453056U, 66584384U, 66715328U, 66846656U, 66977728U, 67108672U, + 67239104U, 67370432U, 67501888U, 67631296U, 67763776U, 67895104U, 68026304U, + 68157248U, 68287936U, 68419264U, 68548288U, 68681408U, 68811968U, 68942912U, + 69074624U, 69205568U, 69337024U, 69467584U, 69599168U, 69729472U, 69861184U, + 69989824U, 70122944U, 70253888U, 70385344U, 70515904U, 70647232U, 70778816U, + 70907968U, 71040832U, 71171648U, 71303104U, 71432512U, 71564992U, 71695168U, + 71826368U, 71958464U, 72089536U, 72219712U, 72350144U, 72482624U, 72613568U, + 72744512U, 72875584U, 73006144U, 73138112U, 73268672U, 73400128U, 73530944U, + 73662272U, 73793344U, 73924544U, 74055104U, 74185792U, 74316992U, 74448832U, + 74579392U, 74710976U, 74841664U, 74972864U, 75102784U, 75233344U, 75364544U, + 75497024U, 75627584U, 75759296U, 75890624U, 76021696U, 76152256U, 76283072U, + 76414144U, 76545856U, 76676672U, 76806976U, 76937792U, 77070016U, 77200832U, + 77331392U, 77462464U, 77593664U, 77725376U, 77856448U, 77987776U, 78118336U, + 78249664U, 78380992U, 78511424U, 78642496U, 78773056U, 78905152U, 79033664U, + 79166656U, 79297472U, 79429568U, 79560512U, 79690816U, 79822784U, 79953472U, + 80084672U, 80214208U, 80346944U, 80477632U, 80608576U, 80740288U, 80870848U, + 81002048U, 81133504U, 81264448U, 81395648U, 81525952U, 81657536U, 81786304U, + 81919808U, 82050112U, 82181312U, 82311616U, 82443968U, 82573376U, 82705984U, + 82835776U, 82967744U, 83096768U, 83230528U, 83359552U, 83491264U, 83622464U, + 83753536U, 83886016U, 84015296U, 84147776U, 84277184U, 84409792U, 84540608U, + 84672064U, 84803008U, 84934336U, 85065152U, 85193792U, 85326784U, 85458496U, + 85589312U, 85721024U, 85851968U, 85982656U, 86112448U, 86244416U, 86370112U, + 86506688U, 86637632U, 86769344U, 86900672U, 87031744U, 87162304U, 87293632U, + 87424576U, 87555392U, 87687104U, 87816896U, 87947968U, 88079168U, 88211264U, + 88341824U, 88473152U, 88603712U, 88735424U, 88862912U, 88996672U, 89128384U, + 89259712U, 89390272U, 89521984U, 89652544U, 89783872U, 89914816U, 90045376U, + 90177088U, 90307904U, 90438848U, 90569152U, 90700096U, 90832832U, 90963776U, + 91093696U, 91223744U, 91356992U, 91486784U, 91618496U, 91749824U, 91880384U, + 92012224U, 92143552U, 92273344U, 92405696U, 92536768U, 92666432U, 92798912U, + 92926016U, 93060544U, 93192128U, 93322816U, 93453632U, 93583936U, 93715136U, + 93845056U, 93977792U, 94109504U, 94240448U, 94371776U, 94501184U, 94632896U, + 94764224U, 94895552U, 95023424U, 95158208U, 95287744U, 95420224U, 95550016U, + 95681216U, 95811904U, 95943872U, 96075328U, 96203584U, 96337856U, 96468544U, + 96599744U, 96731072U, 96860992U, 96992576U, 97124288U, 97254848U, 97385536U, + 97517248U, 97647808U, 97779392U, 97910464U, 98041408U, 98172608U, 98303168U, + 98434496U, 98565568U, 98696768U, 98827328U, 98958784U, 99089728U, 99220928U, + 99352384U, 99482816U, 99614272U, 99745472U, 99876416U, 100007104U, + 100138048U, 100267072U, 100401088U, 100529984U, 100662592U, 100791872U, + 100925248U, 101056064U, 101187392U, 101317952U, 101449408U, 101580608U, + 101711296U, 101841728U, 101973824U, 102104896U, 102235712U, 102366016U, + 102498112U, 102628672U, 102760384U, 102890432U, 103021888U, 103153472U, + 103284032U, 103415744U, 103545152U, 103677248U, 103808576U, 103939648U, + 104070976U, 104201792U, 104332736U, 104462528U, 104594752U, 104725952U, + 104854592U, 104988608U, 105118912U, 105247808U, 105381184U, 105511232U, + 105643072U, 105774784U, 105903296U, 106037056U, 106167872U, 106298944U, + 106429504U, 106561472U, 106691392U, 106822592U, 106954304U, 107085376U, + 107216576U, 107346368U, 107478464U, 107609792U, 107739712U, 107872192U, + 108003136U, 108131392U, 108265408U, 108396224U, 108527168U, 108657344U, + 108789568U, 108920384U, 109049792U, 109182272U, 109312576U, 109444928U, + 109572928U, 109706944U, 109837888U, 109969088U, 110099648U, 110230976U, + 110362432U, 110492992U, 110624704U, 110755264U, 110886208U, 111017408U, + 111148864U, 111279296U, 111410752U, 111541952U, 111673024U, 111803456U, + 111933632U, 112066496U, 112196416U, 112328512U, 112457792U, 112590784U, + 112715968U, 112852672U, 112983616U, 113114944U, 113244224U, 113376448U, + 113505472U, 113639104U, 113770304U, 113901376U, 114031552U, 114163264U, + 114294592U, 114425536U, 114556864U, 114687424U, 114818624U, 114948544U, + 115080512U, 115212224U, 115343296U, 115473472U, 115605184U, 115736128U, + 115867072U, 115997248U, 116128576U, 116260288U, 116391488U, 116522944U, + 116652992U, 116784704U, 116915648U, 117046208U, 117178304U, 117308608U, + 117440192U, 117569728U, 117701824U, 117833024U, 117964096U, 118094656U, + 118225984U, 118357312U, 118489024U, 118617536U, 118749632U, 118882112U, + 119012416U, 119144384U, 119275328U, 119406016U, 119537344U, 119668672U, + 119798464U, 119928896U, 120061376U, 120192832U, 120321728U, 120454336U, + 120584512U, 120716608U, 120848192U, 120979136U, 121109056U, 121241408U, + 121372352U, 121502912U, 121634752U, 121764416U, 121895744U, 122027072U, + 122157632U, 122289088U, 122421184U, 122550592U, 122682944U, 122813888U, + 122945344U, 123075776U, 123207488U, 123338048U, 123468736U, 123600704U, + 123731264U, 123861952U, 123993664U, 124124608U, 124256192U, 124386368U, + 124518208U, 124649024U, 124778048U, 124911296U, 125041088U, 125173696U, + 125303744U, 125432896U, 125566912U, 125696576U, 125829056U, 125958592U, + 126090304U, 126221248U, 126352832U, 126483776U, 126615232U, 126746432U, + 126876608U, 127008704U, 127139392U, 127270336U, 127401152U, 127532224U, + 127663552U, 127794752U, 127925696U, 128055232U, 128188096U, 128319424U, + 128449856U, 128581312U, 128712256U, 128843584U, 128973632U, 129103808U, + 129236288U, 129365696U, 129498944U, 129629888U, 129760832U, 129892288U, + 130023104U, 130154048U, 130283968U, 130416448U, 130547008U, 130678336U, + 130807616U, 130939456U, 131071552U, 131202112U, 131331776U, 131464384U, + 131594048U, 131727296U, 131858368U, 131987392U, 132120256U, 132250816U, + 132382528U, 132513728U, 132644672U, 132774976U, 132905792U, 133038016U, + 133168832U, 133299392U, 133429312U, 133562048U, 133692992U, 133823296U, + 133954624U, 134086336U, 134217152U, 134348608U, 134479808U, 134607296U, + 134741056U, 134872384U, 135002944U, 135134144U, 135265472U, 135396544U, + 135527872U, 135659072U, 135787712U, 135921472U, 136052416U, 136182848U, + 136313792U, 136444864U, 136576448U, 136707904U, 136837952U, 136970048U, + 137099584U, 137232064U, 137363392U, 137494208U, 137625536U, 137755712U, + 137887424U, 138018368U, 138149824U, 138280256U, 138411584U, 138539584U, + 138672832U, 138804928U, 138936128U, 139066688U, 139196864U, 139328704U, + 139460032U, 139590208U, 139721024U, 139852864U, 139984576U, 140115776U, + 140245696U, 140376512U, 140508352U, 140640064U, 140769856U, 140902336U, + 141032768U, 141162688U, 141294016U, 141426496U, 141556544U, 141687488U, + 141819584U, 141949888U, 142080448U, 142212544U, 142342336U, 142474432U, + 142606144U, 142736192U, 142868288U, 142997824U, 143129408U, 143258944U, + 143392448U, 143523136U, 143653696U, 143785024U, 143916992U, 144045632U, + 144177856U, 144309184U, 144440768U, 144570688U, 144701888U, 144832448U, + 144965056U, 145096384U, 145227584U, 145358656U, 145489856U, 145620928U, + 145751488U, 145883072U, 146011456U, 146144704U, 146275264U, 146407232U, + 146538176U, 146668736U, 146800448U, 146931392U, 147062336U, 147193664U, + 147324224U, 147455936U, 147586624U, 147717056U, 147848768U, 147979456U, + 148110784U, 148242368U, 148373312U, 148503232U, 148635584U, 148766144U, + 148897088U, 149028416U, 149159488U, 149290688U, 149420224U, 149551552U, + 149683136U, 149814976U, 149943616U, 150076352U, 150208064U, 150338624U, + 150470464U, 150600256U, 150732224U, 150862784U, 150993088U, 151125952U, + 151254976U, 151388096U, 151519168U, 151649728U, 151778752U, 151911104U, + 152042944U, 152174144U, 152304704U, 152435648U, 152567488U, 152698816U, + 152828992U, 152960576U, 153091648U, 153222976U, 153353792U, 153484096U, + 153616192U, 153747008U, 153878336U, 154008256U, 154139968U, 154270912U, + 154402624U, 154533824U, 154663616U, 154795712U, 154926272U, 155057984U, + 155188928U, 155319872U, 155450816U, 155580608U, 155712064U, 155843392U, + 155971136U, 156106688U, 156237376U, 156367424U, 156499264U, 156630976U, + 156761536U, 156892352U, 157024064U, 157155008U, 157284416U, 157415872U, + 157545536U, 157677248U, 157810496U, 157938112U, 158071744U, 158203328U, + 158334656U, 158464832U, 158596288U, 158727616U, 158858048U, 158988992U, + 159121216U, 159252416U, 159381568U, 159513152U, 159645632U, 159776192U, + 159906496U, 160038464U, 160169536U, 160300352U, 160430656U, 160563008U, + 160693952U, 160822208U, 160956352U, 161086784U, 161217344U, 161349184U, + 161480512U, 161611456U, 161742272U, 161873216U, 162002752U, 162135872U, + 162266432U, 162397888U, 162529216U, 162660032U, 162790976U, 162922048U, + 163052096U, 163184576U, 163314752U, 163446592U, 163577408U, 163707968U, + 163839296U, 163969984U, 164100928U, 164233024U, 164364224U, 164494912U, + 164625856U, 164756672U, 164887616U, 165019072U, 165150016U, 165280064U, + 165412672U, 165543104U, 165674944U, 165805888U, 165936832U, 166067648U, + 166198336U, 166330048U, 166461248U, 166591552U, 166722496U, 166854208U, + 166985408U, 167116736U, 167246656U, 167378368U, 167508416U, 167641024U, + 167771584U, 167903168U, 168034112U, 168164032U, 168295744U, 168427456U, + 168557632U, 168688448U, 168819136U, 168951616U, 169082176U, 169213504U, + 169344832U, 169475648U, 169605952U, 169738048U, 169866304U, 169999552U, + 170131264U, 170262464U, 170393536U, 170524352U, 170655424U, 170782016U, + 170917696U, 171048896U, 171179072U, 171310784U, 171439936U, 171573184U, + 171702976U, 171835072U, 171966272U, 172097216U, 172228288U, 172359232U, + 172489664U, 172621376U, 172747712U, 172883264U, 173014208U, 173144512U, + 173275072U, 173407424U, 173539136U, 173669696U, 173800768U, 173931712U, + 174063424U, 174193472U, 174325696U, 174455744U, 174586816U, 174718912U, + 174849728U, 174977728U, 175109696U, 175242688U, 175374272U, 175504832U, + 175636288U, 175765696U, 175898432U, 176028992U, 176159936U, 176291264U, + 176422592U, 176552512U, 176684864U, 176815424U, 176946496U, 177076544U, + 177209152U, 177340096U, 177470528U, 177600704U, 177731648U, 177864256U, + 177994816U, 178126528U, 178257472U, 178387648U, 178518464U, 178650176U, + 178781888U, 178912064U, 179044288U, 179174848U, 179305024U, 179436736U, + 179568448U, 179698496U, 179830208U, 179960512U, 180092608U, 180223808U, + 180354752U, 180485696U, 180617152U, 180748096U, 180877504U, 181009984U, + 181139264U, 181272512U, 181402688U, 181532608U, 181663168U, 181795136U, + 181926592U, 182057536U, 182190016U, 182320192U, 182451904U, 182582336U, + 182713792U, 182843072U, 182976064U, 183107264U, 183237056U, 183368384U, + 183494848U, 183631424U, 183762752U, 183893824U, 184024768U, 184154816U, + 184286656U, 184417984U, 184548928U, 184680128U, 184810816U, 184941248U, + 185072704U, 185203904U, 185335616U, 185465408U, 185596352U, 185727296U, + 185859904U, 185989696U, 186121664U, 186252992U, 186383552U, 186514112U, + 186645952U, 186777152U, 186907328U, 187037504U, 187170112U, 187301824U, + 187429184U, 187562048U, 187693504U, 187825472U, 187957184U, 188087104U, + 188218304U, 188349376U, 188481344U, 188609728U, 188743616U, 188874304U, + 189005248U, 189136448U, 189265088U, 189396544U, 189528128U, 189660992U, + 189791936U, 189923264U, 190054208U, 190182848U, 190315072U, 190447424U, + 190577984U, 190709312U, 190840768U, 190971328U, 191102656U, 191233472U, + 191364032U, 191495872U, 191626816U, 191758016U, 191888192U, 192020288U, + 192148928U, 192282176U, 192413504U, 192542528U, 192674752U, 192805952U, + 192937792U, 193068608U, 193198912U, 193330496U, 193462208U, 193592384U, + 193723456U, 193854272U, 193985984U, 194116672U, 194247232U, 194379712U, + 194508352U, 194641856U, 194772544U, 194900672U, 195035072U, 195166016U, + 195296704U, 195428032U, 195558592U, 195690304U, 195818176U, 195952576U, + 196083392U, 196214336U, 196345792U, 196476736U, 196607552U, 196739008U, + 196869952U, 197000768U, 197130688U, 197262784U, 197394368U, 197523904U, + 197656384U, 197787584U, 197916608U, 198049472U, 198180544U, 198310208U, + 198442432U, 198573632U, 198705088U, 198834368U, 198967232U, 199097792U, + 199228352U, 199360192U, 199491392U, 199621696U, 199751744U, 199883968U, + 200014016U, 200146624U, 200276672U, 200408128U, 200540096U, 200671168U, + 200801984U, 200933312U, 201062464U, 201194944U, 201326144U, 201457472U, + 201588544U, 201719744U, 201850816U, 201981632U, 202111552U, 202244032U, + 202374464U, 202505152U, 202636352U, 202767808U, 202898368U, 203030336U, + 203159872U, 203292608U, 203423296U, 203553472U, 203685824U, 203816896U, + 203947712U, 204078272U, 204208192U, 204341056U, 204472256U, 204603328U, + 204733888U, 204864448U, 204996544U, 205125568U, 205258304U, 205388864U, + 205517632U, 205650112U, 205782208U, 205913536U, 206044736U, 206176192U, + 206307008U, 206434496U, 206569024U, 206700224U, 206831168U, 206961856U, + 207093056U, 207223616U, 207355328U, 207486784U, 207616832U, 207749056U, + 207879104U, 208010048U, 208141888U, 208273216U, 208404032U, 208534336U, + 208666048U, 208796864U, 208927424U, 209059264U, 209189824U, 209321792U, + 209451584U, 209582656U, 209715136U, 209845568U, 209976896U, 210106432U, + 210239296U, 210370112U, 210501568U, 210630976U, 210763712U, 210894272U, + 211024832U, 211156672U, 211287616U, 211418176U, 211549376U, 211679296U, + 211812032U, 211942592U, 212074432U, 212204864U, 212334016U, 212467648U, + 212597824U, 212727616U, 212860352U, 212991424U, 213120832U, 213253952U, + 213385024U, 213515584U, 213645632U, 213777728U, 213909184U, 214040128U, + 214170688U, 214302656U, 214433728U, 214564544U, 214695232U, 214826048U, + 214956992U, 215089088U, 215219776U, 215350592U, 215482304U, 215613248U, + 215743552U, 215874752U, 216005312U, 216137024U, 216267328U, 216399296U, + 216530752U, 216661696U, 216790592U, 216923968U, 217054528U, 217183168U, + 217316672U, 217448128U, 217579072U, 217709504U, 217838912U, 217972672U, + 218102848U, 218233024U, 218364736U, 218496832U, 218627776U, 218759104U, + 218888896U, 219021248U, 219151936U, 219281728U, 219413056U, 219545024U, + 219675968U, 219807296U, 219938624U, 220069312U, 220200128U, 220331456U, + 220461632U, 220592704U, 220725184U, 220855744U, 220987072U, 221117888U, + 221249216U, 221378368U, 221510336U, 221642048U, 221772736U, 221904832U, + 222031808U, 222166976U, 222297536U, 222428992U, 222559936U, 222690368U, + 222820672U, 222953152U, 223083968U, 223213376U, 223345984U, 223476928U, + 223608512U, 223738688U, 223869376U, 224001472U, 224132672U, 224262848U, + 224394944U, 224524864U, 224657344U, 224788288U, 224919488U, 225050432U, + 225181504U, 225312704U, 225443776U, 225574592U, 225704768U, 225834176U, + 225966784U, 226097216U, 226229824U, 226360384U, 226491712U, 226623424U, + 226754368U, 226885312U, 227015104U, 227147456U, 227278528U, 227409472U, + 227539904U, 227669696U, 227802944U, 227932352U, 228065216U, 228196288U, + 228326464U, 228457792U, 228588736U, 228720064U, 228850112U, 228981056U, + 229113152U, 229243328U, 229375936U, 229505344U, 229636928U, 229769152U, + 229894976U, 230030272U, 230162368U, 230292416U, 230424512U, 230553152U, + 230684864U, 230816704U, 230948416U, 231079616U, 231210944U, 231342016U, + 231472448U, 231603776U, 231733952U, 231866176U, 231996736U, 232127296U, + 232259392U, 232388672U, 232521664U, 232652608U, 232782272U, 232914496U, + 233043904U, 233175616U, 233306816U, 233438528U, 233569984U, 233699776U, + 233830592U, 233962688U, 234092224U, 234221888U, 234353984U, 234485312U, + 234618304U, 234749888U, 234880832U, 235011776U, 235142464U, 235274048U, + 235403456U, 235535936U, 235667392U, 235797568U, 235928768U, 236057152U, + 236190272U, 236322752U, 236453312U, 236583616U, 236715712U, 236846528U, + 236976448U, 237108544U, 237239104U, 237371072U, 237501632U, 237630784U, + 237764416U, 237895232U, 238026688U, 238157632U, 238286912U, 238419392U, + 238548032U, 238681024U, 238812608U, 238941632U, 239075008U, 239206336U, + 239335232U, 239466944U, 239599168U, 239730496U, 239861312U, 239992384U, + 240122816U, 240254656U, 240385856U, 240516928U, 240647872U, 240779072U, + 240909632U, 241040704U, 241171904U, 241302848U, 241433408U, 241565248U, + 241696192U, 241825984U, 241958848U, 242088256U, 242220224U, 242352064U, + 242481856U, 242611648U, 242744896U, 242876224U, 243005632U, 243138496U, + 243268672U, 243400384U, 243531712U, 243662656U, 243793856U, 243924544U, + 244054592U, 244187072U, 244316608U, 244448704U, 244580032U, 244710976U, + 244841536U, 244972864U, 245104448U, 245233984U, 245365312U, 245497792U, + 245628736U, 245759936U, 245889856U, 246021056U, 246152512U, 246284224U, + 246415168U, 246545344U, 246675904U, 246808384U, 246939584U, 247070144U, + 247199552U, 247331648U, 247463872U, 247593536U, 247726016U, 247857088U, + 247987648U, 248116928U, 248249536U, 248380736U, 248512064U, 248643008U, + 248773312U, 248901056U, 249036608U, 249167552U, 249298624U, 249429184U, + 249560512U, 249692096U, 249822784U, 249954112U, 250085312U, 250215488U, + 250345792U, 250478528U, 250608704U, 250739264U, 250870976U, 251002816U, + 251133632U, 251263552U, 251395136U, 251523904U, 251657792U, 251789248U, + 251919424U, 252051392U, 252182464U, 252313408U, 252444224U, 252575552U, + 252706624U, 252836032U, 252968512U, 253099712U, 253227584U, 253361728U, + 253493056U, 253623488U, 253754432U, 253885504U, 254017216U, 254148032U, + 254279488U, 254410432U, 254541376U, 254672576U, 254803264U, 254933824U, + 255065792U, 255196736U, 255326528U, 255458752U, 255589952U, 255721408U, + 255851072U, 255983296U, 256114624U, 256244416U, 256374208U, 256507712U, + 256636096U, 256768832U, 256900544U, 257031616U, 257162176U, 257294272U, + 257424448U, 257555776U, 257686976U, 257818432U, 257949632U, 258079552U, + 258211136U, 258342464U, 258473408U, 258603712U, 258734656U, 258867008U, + 258996544U, 259127744U, 259260224U, 259391296U, 259522112U, 259651904U, + 259784384U, 259915328U, 260045888U, 260175424U, 260308544U, 260438336U, + 260570944U, 260700992U, 260832448U, 260963776U, 261092672U, 261226304U, + 261356864U, 261487936U, 261619648U, 261750592U, 261879872U, 262011968U, + 262143424U, 262274752U, 262404416U, 262537024U, 262667968U, 262799296U, + 262928704U, 263061184U, 263191744U, 263322944U, 263454656U, 263585216U, + 263716672U, 263847872U, 263978944U, 264108608U, 264241088U, 264371648U, + 264501184U, 264632768U, 264764096U, 264895936U, 265024576U, 265158464U, + 265287488U, 265418432U, 265550528U, 265681216U, 265813312U, 265943488U, + 266075968U, 266206144U, 266337728U, 266468032U, 266600384U, 266731072U, + 266862272U, 266993344U, 267124288U, 267255616U, 267386432U, 267516992U, + 267648704U, 267777728U, 267910592U, 268040512U, 268172096U, 268302784U, + 268435264U, 268566208U, 268696256U, 268828096U, 268959296U, 269090368U, + 269221312U, 269352256U, 269482688U, 269614784U, 269745856U, 269876416U, + 270007616U, 270139328U, 270270272U, 270401216U, 270531904U, 270663616U, + 270791744U, 270924736U, 271056832U, 271186112U, 271317184U, 271449536U, + 271580992U, 271711936U, 271843136U, 271973056U, 272105408U, 272236352U, + 272367296U, 272498368U, 272629568U, 272759488U, 272891456U, 273022784U, + 273153856U, 273284672U, 273415616U, 273547072U, 273677632U, 273808448U, + 273937088U, 274071488U, 274200896U, 274332992U, 274463296U, 274595392U, + 274726208U, 274857536U, 274988992U, 275118656U, 275250496U, 275382208U, + 275513024U, 275643968U, 275775296U, 275906368U, 276037184U, 276167872U, + 276297664U, 276429376U, 276560576U, 276692672U, 276822976U, 276955072U, + 277085632U, 277216832U, 277347008U, 277478848U, 277609664U, 277740992U, + 277868608U, 278002624U, 278134336U, 278265536U, 278395328U, 278526784U, + 278657728U, 278789824U, 278921152U, 279052096U, 279182912U, 279313088U, + 279443776U, 279576256U, 279706048U, 279838528U, 279969728U, 280099648U, + 280230976U, 280361408U, 280493632U, 280622528U, 280755392U, 280887104U, + 281018176U, 281147968U, 281278912U, 281411392U, 281542592U, 281673152U, + 281803712U, 281935552U, 282066496U, 282197312U, 282329024U, 282458816U, + 282590272U, 282720832U, 282853184U, 282983744U, 283115072U, 283246144U, + 283377344U, 283508416U, 283639744U, 283770304U, 283901504U, 284032576U, + 284163136U, 284294848U, 284426176U, 284556992U, 284687296U, 284819264U, + 284950208U, 285081536U +}; + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libetchash/dllmain.cpp b/src/Native/libetchash/dllmain.cpp new file mode 100644 index 000000000..69b58914b --- /dev/null +++ b/src/Native/libetchash/dllmain.cpp @@ -0,0 +1,19 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/src/Native/libetchash/endian.h b/src/Native/libetchash/endian.h new file mode 100644 index 000000000..5b8abf03d --- /dev/null +++ b/src/Native/libetchash/endian.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include "compiler.h" + +#if defined(__MINGW32__) || defined(_WIN32) + # define LITTLE_ENDIAN 1234 + # define BYTE_ORDER LITTLE_ENDIAN +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) + # include +#elif defined(__OpenBSD__) || defined(__SVR4) + # include +#elif defined(__APPLE__) +# include +#elif defined( BSD ) && (BSD >= 199103) + # include +#elif defined( __QNXNTO__ ) && defined( __LITTLEENDIAN__ ) + # define LITTLE_ENDIAN 1234 + # define BYTE_ORDER LITTLE_ENDIAN +#elif defined( __QNXNTO__ ) && defined( __BIGENDIAN__ ) + # define BIG_ENDIAN 1234 + # define BYTE_ORDER BIG_ENDIAN +#else +# include +#endif + +#if defined(_WIN32) +#include +#define ethash_swap_u32(input_) _byteswap_ulong(input_) +#define ethash_swap_u64(input_) _byteswap_uint64(input_) +#elif defined(__APPLE__) +#include +#define ethash_swap_u32(input_) OSSwapInt32(input_) +#define ethash_swap_u64(input_) OSSwapInt64(input_) +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) +#define ethash_swap_u32(input_) bswap32(input_) +#define ethash_swap_u64(input_) bswap64(input_) +#elif defined(__OpenBSD__) +#include +#define ethash_swap_u32(input_) swap32(input_) +#define ethash_swap_u64(input_) swap64(input_) +#else // posix +#include +#define ethash_swap_u32(input_) bswap_32(input_) +#define ethash_swap_u64(input_) bswap_64(input_) +#endif + + +#if LITTLE_ENDIAN == BYTE_ORDER + +#define fix_endian32(dst_ ,src_) dst_ = src_ +#define fix_endian32_same(val_) +#define fix_endian64(dst_, src_) dst_ = src_ +#define fix_endian64_same(val_) +#define fix_endian_arr32(arr_, size_) +#define fix_endian_arr64(arr_, size_) + +#elif BIG_ENDIAN == BYTE_ORDER + +#define fix_endian32(dst_, src_) dst_ = ethash_swap_u32(src_) +#define fix_endian32_same(val_) val_ = ethash_swap_u32(val_) +#define fix_endian64(dst_, src_) dst_ = ethash_swap_u64(src_) +#define fix_endian64_same(val_) val_ = ethash_swap_u64(val_) +#define fix_endian_arr32(arr_, size_) \ + do { \ + for (unsigned i_ = 0; i_ < (size_); ++i_) { \ + arr_[i_] = ethash_swap_u32(arr_[i_]); \ + } \ + } while (0) +#define fix_endian_arr64(arr_, size_) \ + do { \ + for (unsigned i_ = 0; i_ < (size_); ++i_) { \ + arr_[i_] = ethash_swap_u64(arr_[i_]); \ + } \ + } while (0) +#else +# error "endian not supported" +#endif // BYTE_ORDER diff --git a/src/Native/libetchash/ethash.h b/src/Native/libetchash/ethash.h new file mode 100644 index 000000000..875f5e891 --- /dev/null +++ b/src/Native/libetchash/ethash.h @@ -0,0 +1,152 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ + +/** @file ethash.h +* @date 2015 +*/ +#pragma once + +#include +#include +#include +#include +#include "compiler.h" + +#define ETHASH_REVISION 23 +#define ETHASH_DATASET_BYTES_INIT 1073741824U // 2**30 +#define ETHASH_DATASET_BYTES_GROWTH 8388608U // 2**23 +#define ETHASH_CACHE_BYTES_INIT 1073741824U // 2**24 +#define ETHASH_CACHE_BYTES_GROWTH 131072U // 2**17 +#define ETHASH_EPOCH_LENGTH 30000U +#define ETHASH_EPOCH_LENGTH_NEW 60000U +#define ETCHASH_FORK_BLOCK 11700000 // classic mainnet +//#define ETCHASH_FORK_BLOCK 2520000 // mordor +#define ETHASH_MIX_BYTES 128 +#define ETHASH_HASH_BYTES 64 +#define ETHASH_DATASET_PARENTS 256 +#define ETHASH_CACHE_ROUNDS 3 +#define ETHASH_ACCESSES 64 +#define ETHASH_DAG_MAGIC_NUM_SIZE 8 +#define ETHASH_DAG_MAGIC_NUM 0xFEE1DEADBADDCAFE + +#ifdef __cplusplus +extern "C" { +#endif + +/// Type of a seedhash/blockhash e.t.c. +typedef struct ethash_h256 { uint8_t b[32]; } ethash_h256_t; + +// convenience macro to statically initialize an h256_t +// usage: +// ethash_h256_t a = ethash_h256_static_init(1, 2, 3, ... ) +// have to provide all 32 values. If you don't provide all the rest +// will simply be unitialized (not guranteed to be 0) +#define ethash_h256_static_init(...) \ + { {__VA_ARGS__} } + +struct ethash_light; +typedef struct ethash_light* ethash_light_t; +struct ethash_full; +typedef struct ethash_full* ethash_full_t; +typedef int(*ethash_callback_t)(unsigned); + +#pragma pack(push, 1) +typedef struct ethash_return_value { + ethash_h256_t result; + ethash_h256_t mix_hash; + bool success; +} ethash_return_value_t; +#pragma pack(pop) + +/** + * Allocate and initialize a new ethash_light handler + * + * @param block_number The block number for which to create the handler + * @return Newly allocated ethash_light handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes() + */ +ethash_light_t ethash_light_new(uint64_t block_number); +/** + * Frees a previously allocated ethash_light handler + * @param light The light handler to free + */ +void ethash_light_delete(ethash_light_t light); +/** + * Calculate the light client data + * + * @param light The light client handler + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return an object of ethash_return_value_t holding the return values + */ +ethash_return_value_t ethash_light_compute( + ethash_light_t light, + ethash_h256_t const header_hash, + uint64_t nonce +); + +/** + * Allocate and initialize a new ethash_full handler + * + * @param light The light handler containing the cache. + * @param callback A callback function with signature of @ref ethash_callback_t + * It accepts an unsigned with which a progress of DAG calculation + * can be displayed. If all goes well the callback should return 0. + * If a non-zero value is returned then DAG generation will stop. + * Be advised. A progress value of 100 means that DAG creation is + * almost complete and that this function will soon return succesfully. + * It does not mean that the function has already had a succesfull return. + * @return Newly allocated ethash_full handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data() + */ +ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback); + +/** + * Frees a previously allocated ethash_full handler + * @param full The light handler to free + */ +void ethash_full_delete(ethash_full_t full); +/** + * Calculate the full client data + * + * @param full The full client handler + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return An object of ethash_return_value to hold the return value + */ +ethash_return_value_t ethash_full_compute( + ethash_full_t full, + ethash_h256_t const header_hash, + uint64_t nonce +); +/** + * Get a pointer to the full DAG data + */ +void const* ethash_full_dag(ethash_full_t full); +/** + * Get the size of the DAG data + */ +uint64_t ethash_full_dag_size(ethash_full_t full); + +/** + * Calculate the seedhash for a given block number + */ +ethash_h256_t ethash_get_seedhash(uint64_t block_number); + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libetchash/exports.cpp b/src/Native/libetchash/exports.cpp new file mode 100644 index 000000000..506cb149c --- /dev/null +++ b/src/Native/libetchash/exports.cpp @@ -0,0 +1,98 @@ +/* +Copyright 2017 Coin Foundry (coinfoundry.org) +Authors: Oliver Weichhold (oliver@weichhold.com) +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "sha3.h" +#include "internal.h" +#include "ethash.h" + +extern "C" bool ethash_get_default_dirname(char* strbuf, size_t buffsize); + +#ifdef _WIN32 +#define MODULE_API __declspec(dllexport) +#else +#define MODULE_API +#endif + +extern "C" MODULE_API uint64_t ethash_get_datasize_export(uint64_t const block_number) +{ + return ethash_get_datasize(block_number); +} + +extern "C" MODULE_API uint64_t ethash_get_cachesize_export(uint64_t const block_number) +{ + return ethash_get_cachesize(block_number); +} + +extern "C" MODULE_API ethash_light_t ethash_light_new_export(uint64_t block_number) +{ + return ethash_light_new(block_number); +} + +extern "C" MODULE_API void ethash_light_delete_export(ethash_light_t light) +{ + ethash_light_delete(light); +} + +extern "C" MODULE_API void ethash_light_compute_export( + ethash_light_t light, + ethash_h256_t const *header_hash, + uint64_t nonce, + ethash_return_value_t *result) +{ + *result = ethash_light_compute(light, *header_hash, nonce); +} + +extern "C" MODULE_API ethash_full_t ethash_full_new_export(const char *dirname, ethash_light_t light, ethash_callback_t callback) +{ + uint64_t full_size = ethash_get_datasize(light->block_number); + ethash_h256_t seedhash = ethash_get_seedhash(light->block_number); + return ethash_full_new_internal(dirname, seedhash, full_size, light, callback); +} + +extern "C" MODULE_API void ethash_full_delete_export(ethash_full_t full) +{ + ethash_full_delete(full); +} + +extern "C" MODULE_API void ethash_full_compute_export( + ethash_full_t full, + ethash_h256_t const *header_hash, + uint64_t nonce, + ethash_return_value_t *result) +{ + *result = ethash_full_compute(full, *header_hash, nonce); +} + +extern "C" MODULE_API void const* ethash_full_dag_export(ethash_full_t full) +{ + return ethash_full_dag(full); +} + +extern "C" MODULE_API uint64_t ethash_full_dag_size_export(ethash_full_t full) +{ + return ethash_full_dag_size(full); +} + +extern "C" MODULE_API ethash_h256_t ethash_get_seedhash_export(uint64_t block_number) +{ + return ethash_get_seedhash(block_number); +} + +extern "C" MODULE_API bool ethash_get_default_dirname_export(char *buf, size_t buf_size) +{ + return ethash_get_default_dirname(buf, buf_size); +} diff --git a/src/Native/libetchash/fnv.h b/src/Native/libetchash/fnv.h new file mode 100644 index 000000000..82cd655c4 --- /dev/null +++ b/src/Native/libetchash/fnv.h @@ -0,0 +1,43 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: 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. + + cpp-ethereum 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. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file fnv.h +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +#pragma once +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FNV_PRIME 0x01000193 + +/* The FNV-1 spec multiplies the prime with the input one byte (octet) in turn. + We instead multiply it with the full 32-bit input. + This gives a different result compared to a canonical FNV-1 implementation. +*/ +static inline uint32_t fnv_hash(uint32_t const x, uint32_t const y) +{ + return x * FNV_PRIME ^ y; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libetchash/internal.c b/src/Native/libetchash/internal.c new file mode 100644 index 000000000..3ab113d47 --- /dev/null +++ b/src/Native/libetchash/internal.c @@ -0,0 +1,515 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file internal.c +* @author Tim Hughes +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +#include +#include +#include +#include +#include +#include "mmap.h" +#include "ethash.h" +#include "fnv.h" +#include "endian.h" +#include "internal.h" +#include "data_sizes.h" +#include "io.h" + +#ifdef WITH_CRYPTOPP + +#include "sha3_cryptopp.h" + +#else +#include "sha3.h" +#endif // WITH_CRYPTOPP + +#if defined(_MSC_VER) +#include +#endif + +uint64_t ethash_get_datasize(uint64_t const block_number) +{ + return dag_sizes[etchash_calc_epoch(block_number)]; +} + +uint64_t ethash_get_cachesize(uint64_t const block_number) +{ + return cache_sizes[etchash_calc_epoch(block_number)]; +} + +// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) +// https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf +// SeqMemoHash(s, R, N) +bool static ethash_compute_cache_nodes( + node* const nodes, + uint64_t cache_size, + ethash_h256_t const* seed +) +{ + if (cache_size % sizeof(node) != 0) { + return false; + } + uint32_t const num_nodes = (uint32_t) (cache_size / sizeof(node)); + + SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32); + + for (uint32_t i = 1; i != num_nodes; ++i) { + SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64); + } + + for (uint32_t j = 0; j != ETHASH_CACHE_ROUNDS; j++) { + for (uint32_t i = 0; i != num_nodes; i++) { + uint32_t const idx = nodes[i].words[0] % num_nodes; + node data; + data = nodes[(num_nodes - 1 + i) % num_nodes]; + for (uint32_t w = 0; w != NODE_WORDS; ++w) { + data.words[w] ^= nodes[idx].words[w]; + } + SHA3_512(nodes[i].bytes, data.bytes, sizeof(data)); + } + } + + // now perform endian conversion + fix_endian_arr32(nodes->words, num_nodes * NODE_WORDS); + return true; +} + +void ethash_calculate_dag_item( + node* const ret, + uint32_t node_index, + ethash_light_t const light +) +{ + uint32_t num_parent_nodes = (uint32_t) (light->cache_size / sizeof(node)); + node const* cache_nodes = (node const *) light->cache; + node const* init = &cache_nodes[node_index % num_parent_nodes]; + memcpy(ret, init, sizeof(node)); + ret->words[0] ^= node_index; + SHA3_512(ret->bytes, ret->bytes, sizeof(node)); +#if defined(_M_X64) && HAVE_SSE2 + __m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME); + __m128i xmm0 = ret->xmm[0]; + __m128i xmm1 = ret->xmm[1]; + __m128i xmm2 = ret->xmm[2]; + __m128i xmm3 = ret->xmm[3]; +#endif + + for (uint32_t i = 0; i != ETHASH_DATASET_PARENTS; ++i) { + uint32_t parent_index = fnv_hash(node_index ^ i, ret->words[i % NODE_WORDS]) % num_parent_nodes; + node const *parent = &cache_nodes[parent_index]; + +#if defined(_M_X64) && HAVE_SSE2 + { + xmm0 = _mm_mullo_epi32(xmm0, fnv_prime); + xmm1 = _mm_mullo_epi32(xmm1, fnv_prime); + xmm2 = _mm_mullo_epi32(xmm2, fnv_prime); + xmm3 = _mm_mullo_epi32(xmm3, fnv_prime); + xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]); + xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]); + xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]); + xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]); + + // have to write to ret as values are used to compute index + ret->xmm[0] = xmm0; + ret->xmm[1] = xmm1; + ret->xmm[2] = xmm2; + ret->xmm[3] = xmm3; + } + #else + { + for (unsigned w = 0; w != NODE_WORDS; ++w) { + ret->words[w] = fnv_hash(ret->words[w], parent->words[w]); + } + } +#endif + } + SHA3_512(ret->bytes, ret->bytes, sizeof(node)); +} + +bool ethash_compute_full_data( + void* mem, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +) +{ + if (full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 || + (full_size % sizeof(node)) != 0) { + return false; + } + uint32_t const max_n = (uint32_t)(full_size / sizeof(node)); + node* full_nodes = mem; + double const progress_change = 1.0f / max_n; + double progress = 0.0f; + // now compute full nodes + for (uint32_t n = 0; n != max_n; ++n) { + if (callback && + n % (max_n / 100) == 0 && + callback((unsigned int)(ceil(progress * 100.0f))) != 0) { + + return false; + } + progress += progress_change; + ethash_calculate_dag_item(&(full_nodes[n]), n, light); + } + return true; +} + +static bool ethash_hash( + ethash_return_value_t* ret, + node const* full_nodes, + ethash_light_t const light, + uint64_t full_size, + ethash_h256_t const header_hash, + uint64_t const nonce +) +{ + if (full_size % MIX_WORDS != 0) { + return false; + } + + // pack hash and nonce together into first 40 bytes of s_mix + assert(sizeof(node) * 8 == 512); + node s_mix[MIX_NODES + 1]; + memcpy(s_mix[0].bytes, &header_hash, 32); + fix_endian64(s_mix[0].double_words[4], nonce); + + // compute sha3-512 hash and replicate across mix + SHA3_512(s_mix->bytes, s_mix->bytes, 40); + fix_endian_arr32(s_mix[0].words, 16); + + node* const mix = s_mix + 1; + for (uint32_t w = 0; w != MIX_WORDS; ++w) { + mix->words[w] = s_mix[0].words[w % NODE_WORDS]; + } + + unsigned const page_size = sizeof(uint32_t) * MIX_WORDS; + unsigned const num_full_pages = (unsigned) (full_size / page_size); + + for (unsigned i = 0; i != ETHASH_ACCESSES; ++i) { + uint32_t const index = fnv_hash(s_mix->words[0] ^ i, mix->words[i % MIX_WORDS]) % num_full_pages; + + for (unsigned n = 0; n != MIX_NODES; ++n) { + node const* dag_node; + if (full_nodes) { + dag_node = &full_nodes[MIX_NODES * index + n]; + } else { + node tmp_node; + ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, light); + dag_node = &tmp_node; + } + +#if defined(_M_X64) && HAVE_SSE2 + { + __m128i fnv_prime = _mm_set1_epi32(FNV_PRIME); + __m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]); + __m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]); + __m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]); + __m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]); + mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]); + mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]); + mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]); + mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]); + } + #else + { + for (unsigned w = 0; w != NODE_WORDS; ++w) { + mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]); + } + } +#endif + } + + } + + // compress mix + for (uint32_t w = 0; w != MIX_WORDS; w += 4) { + uint32_t reduction = mix->words[w + 0]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 1]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 2]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 3]; + mix->words[w / 4] = reduction; + } + + fix_endian_arr32(mix->words, MIX_WORDS / 4); + memcpy(&ret->mix_hash, mix->bytes, 32); + // final Keccak hash + SHA3_256(&ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix) + return true; +} + +void ethash_quick_hash( + ethash_h256_t* return_hash, + ethash_h256_t const* header_hash, + uint64_t nonce, + ethash_h256_t const* mix_hash +) +{ + uint8_t buf[64 + 32]; + memcpy(buf, header_hash, 32); + fix_endian64_same(nonce); + memcpy(&(buf[32]), &nonce, 8); + SHA3_512(buf, buf, 40); + memcpy(&(buf[64]), mix_hash, 32); + SHA3_256(return_hash, buf, 64 + 32); +} + +ethash_h256_t ethash_get_seedhash(uint64_t block_number) +{ + ethash_h256_t ret; + ethash_h256_reset(&ret); + uint64_t const epochs = block_number / ETHASH_EPOCH_LENGTH; + for (uint32_t i = 0; i < epochs; ++i) + SHA3_256(&ret, (uint8_t*)&ret, 32); + return ret; +} + +bool ethash_quick_check_difficulty( + ethash_h256_t const* header_hash, + uint64_t const nonce, + ethash_h256_t const* mix_hash, + ethash_h256_t const* boundary +) +{ + + ethash_h256_t return_hash; + ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash); + return ethash_check_difficulty(&return_hash, boundary); +} + +ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed) +{ + struct ethash_light *ret; + ret = calloc(sizeof(*ret), 1); + if (!ret) { + return NULL; + } + ret->cache = malloc((size_t)cache_size); + if (!ret->cache) { + goto fail_free_light; + } + node* nodes = (node*)ret->cache; + if (!ethash_compute_cache_nodes(nodes, cache_size, seed)) { + goto fail_free_cache_mem; + } + ret->cache_size = cache_size; + return ret; + +fail_free_cache_mem: + free(ret->cache); +fail_free_light: + free(ret); + return NULL; +} + +ethash_light_t ethash_light_new(uint64_t block_number) +{ + ethash_h256_t seedhash = ethash_get_seedhash(block_number); + ethash_light_t ret; + ret = ethash_light_new_internal(ethash_get_cachesize(block_number), &seedhash); + ret->block_number = block_number; + return ret; +} + +void ethash_light_delete(ethash_light_t light) +{ + if (light->cache) { + free(light->cache); + } + free(light); +} + +uint64_t static etchash_calc_epoch(uint64_t const block_number) +{ + uint64_t epochLen = block_number >= ETCHASH_FORK_BLOCK ? ETHASH_EPOCH_LENGTH_NEW : ETHASH_EPOCH_LENGTH; + return block_number / epochLen; +} + +ethash_return_value_t ethash_light_compute_internal( + ethash_light_t light, + uint64_t full_size, + ethash_h256_t const header_hash, + uint64_t nonce +) +{ + ethash_return_value_t ret; + ret.success = true; + if (!ethash_hash(&ret, NULL, light, full_size, header_hash, nonce)) { + ret.success = false; + } + return ret; +} + +ethash_return_value_t ethash_light_compute( + ethash_light_t light, + ethash_h256_t const header_hash, + uint64_t nonce +) +{ + uint64_t full_size = ethash_get_datasize(light->block_number); + return ethash_light_compute_internal(light, full_size, header_hash, nonce); +} + +static bool ethash_mmap(struct ethash_full* ret, FILE* f) +{ + int fd; + char* mmapped_data; + errno = 0; + ret->file = f; + if ((fd = ethash_fileno(ret->file)) == -1) { + return false; + } + mmapped_data= mmap( + NULL, + (size_t)ret->file_size + ETHASH_DAG_MAGIC_NUM_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0 + ); + if (mmapped_data == MAP_FAILED) { + return false; + } + ret->data = (node*)(mmapped_data + ETHASH_DAG_MAGIC_NUM_SIZE); + return true; +} + +ethash_full_t ethash_full_new_internal( + char const* dirname, + ethash_h256_t const seed_hash, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +) +{ + struct ethash_full* ret; + FILE *f = NULL; + ret = calloc(sizeof(*ret), 1); + if (!ret) { + return NULL; + } + ret->file_size = (size_t)full_size; + switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) { + case ETHASH_IO_FAIL: + // ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case + goto fail_free_full; + case ETHASH_IO_MEMO_MATCH: + if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); + goto fail_close_file; + } + return ret; + case ETHASH_IO_MEMO_SIZE_MISMATCH: + // if a DAG of same filename but unexpected size is found, silently force new file creation + if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) { + ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size."); + goto fail_free_full; + } + // fallthrough to the mismatch case here, DO NOT go through match + case ETHASH_IO_MEMO_MISMATCH: + if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); + goto fail_close_file; + } + break; + } + + if (!ethash_compute_full_data(ret->data, full_size, light, callback)) { + ETHASH_CRITICAL("Failure at computing DAG data."); + goto fail_free_full_data; + } + + // after the DAG has been filled then we finalize it by writting the magic number at the beginning + if (fseek(f, 0, SEEK_SET) != 0) { + ETHASH_CRITICAL("Could not seek to DAG file start to write magic number."); + goto fail_free_full_data; + } + uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM; + if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { + ETHASH_CRITICAL("Could not write magic number to DAG's beginning."); + goto fail_free_full_data; + } + if (fflush(f) != 0) {// make sure the magic number IS there + ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?"); + goto fail_free_full_data; + } + return ret; + +fail_free_full_data: + // could check that munmap(..) == 0 but even if it did not can't really do anything here + munmap(ret->data, (size_t)full_size); +fail_close_file: + fclose(ret->file); +fail_free_full: + free(ret); + return NULL; +} + +ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback) +{ + char strbuf[256]; + if (!ethash_get_default_dirname(strbuf, 256)) { + return NULL; + } + uint64_t full_size = ethash_get_datasize(light->block_number); + ethash_h256_t seedhash = ethash_get_seedhash(light->block_number); + return ethash_full_new_internal(strbuf, seedhash, full_size, light, callback); +} + +void ethash_full_delete(ethash_full_t full) +{ + // could check that munmap(..) == 0 but even if it did not can't really do anything here + munmap(full->data, (size_t)full->file_size); + if (full->file) { + fclose(full->file); + } + free(full); +} + +ethash_return_value_t ethash_full_compute( + ethash_full_t full, + ethash_h256_t const header_hash, + uint64_t nonce +) +{ + ethash_return_value_t ret; + ret.success = true; + if (!ethash_hash( + &ret, + (node const*)full->data, + NULL, + full->file_size, + header_hash, + nonce)) { + ret.success = false; + } + return ret; +} + +void const* ethash_full_dag(ethash_full_t full) +{ + return full->data; +} + +uint64_t ethash_full_dag_size(ethash_full_t full) +{ + return full->file_size; +} diff --git a/src/Native/libetchash/internal.h b/src/Native/libetchash/internal.h new file mode 100644 index 000000000..7d630d272 --- /dev/null +++ b/src/Native/libetchash/internal.h @@ -0,0 +1,178 @@ +#pragma once +#include "compiler.h" +#include "endian.h" +#include "ethash.h" +#include + +#if defined(_M_X64) && HAVE_SSE2 +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// compile time settings +#define NODE_WORDS (64/4) +#define MIX_WORDS (ETHASH_MIX_BYTES/4) +#define MIX_NODES (MIX_WORDS / NODE_WORDS) +#include + +typedef union node { + uint8_t bytes[NODE_WORDS * 4]; + uint32_t words[NODE_WORDS]; + uint64_t double_words[NODE_WORDS / 2]; + +#if defined(_M_X64) && HAVE_SSE2 + __m128i xmm[NODE_WORDS/4]; +#endif + +} node; + +static inline uint8_t ethash_h256_get(ethash_h256_t const* hash, unsigned int i) +{ + return hash->b[i]; +} + +static inline void ethash_h256_set(ethash_h256_t* hash, unsigned int i, uint8_t v) +{ + hash->b[i] = v; +} + +static inline void ethash_h256_reset(ethash_h256_t* hash) +{ + memset(hash, 0, 32); +} + +// Returns if hash is less than or equal to boundary (2^256/difficulty) +static inline bool ethash_check_difficulty( + ethash_h256_t const* hash, + ethash_h256_t const* boundary +) +{ + // Boundary is big endian + for (int i = 0; i < 32; i++) { + if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) { + continue; + } + return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i); + } + return true; +} + +/** + * Difficulty quick check for POW preverification + * + * @param header_hash The hash of the header + * @param nonce The block's nonce + * @param mix_hash The mix digest hash + * @param boundary The boundary is defined as (2^256 / difficulty) + * @return true for succesful pre-verification and false otherwise + */ +bool ethash_quick_check_difficulty( + ethash_h256_t const* header_hash, + uint64_t const nonce, + ethash_h256_t const* mix_hash, + ethash_h256_t const* boundary +); + +struct ethash_light { + void* cache; + uint64_t cache_size; + uint64_t block_number; +}; + +/** + * Allocate and initialize a new ethash_light handler. Internal version + * + * @param cache_size The size of the cache in bytes + * @param seed Block seedhash to be used during the computation of the + * cache nodes + * @return Newly allocated ethash_light handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes() + */ +ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed); + +/** + * Calculate the light client data. Internal version. + * + * @param light The light client handler + * @param full_size The size of the full data in bytes. + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return The resulting hash. + */ +ethash_return_value_t ethash_light_compute_internal( + ethash_light_t light, + uint64_t full_size, + ethash_h256_t const header_hash, + uint64_t nonce +); + +struct ethash_full { + FILE* file; + uint64_t file_size; + node* data; +}; + +/** + * Allocate and initialize a new ethash_full handler. Internal version. + * + * @param dirname The directory in which to put the DAG file. + * @param seedhash The seed hash of the block. Used in the DAG file naming. + * @param full_size The size of the full data in bytes. + * @param cache A cache object to use that was allocated with @ref ethash_cache_new(). + * Iff this function succeeds the ethash_full_t will take memory + * memory ownership of the cache and free it at deletion. If + * not then the user still has to handle freeing of the cache himself. + * @param callback A callback function with signature of @ref ethash_callback_t + * It accepts an unsigned with which a progress of DAG calculation + * can be displayed. If all goes well the callback should return 0. + * If a non-zero value is returned then DAG generation will stop. + * @return Newly allocated ethash_full handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data() + */ +ethash_full_t ethash_full_new_internal( + char const* dirname, + ethash_h256_t const seed_hash, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +); + +void ethash_calculate_dag_item( + node* const ret, + uint32_t node_index, + ethash_light_t const cache +); + +void ethash_quick_hash( + ethash_h256_t* return_hash, + ethash_h256_t const* header_hash, + const uint64_t nonce, + ethash_h256_t const* mix_hash +); + +uint64_t ethash_get_datasize(uint64_t const block_number); +uint64_t ethash_get_cachesize(uint64_t const block_number); +static uint64_t etchash_calc_epoch(uint64_t const block_number); + +/** + * Compute the memory data for a full node's memory + * + * @param mem A pointer to an ethash full's memory + * @param full_size The size of the full data in bytes + * @param cache A cache object to use in the calculation + * @param callback The callback function. Check @ref ethash_full_new() for details. + * @return true if all went fine and false for invalid parameters + */ +bool ethash_compute_full_data( + void* mem, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +); + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libetchash/io.c b/src/Native/libetchash/io.c new file mode 100644 index 000000000..e73939181 --- /dev/null +++ b/src/Native/libetchash/io.c @@ -0,0 +1,128 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file io.c + * @author Lefteris Karapetsas + * @date 2015 + */ +#include "io.h" +#include +#include +#include + +int ethash_fseek(FILE* f, size_t offset, int origin) +{ +#ifdef _WIN32 + return _fseeki64(f, offset, origin); +#else + return fseeko(f, offset, origin); +#endif +} + +enum ethash_io_rc ethash_io_prepare( + char const* dirname, + ethash_h256_t const seedhash, + FILE** output_file, + uint64_t file_size, + bool force_create +) +{ + char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE]; + enum ethash_io_rc ret = ETHASH_IO_FAIL; + // reset errno before io calls + errno = 0; + + // assert directory exists + if (!ethash_mkdir(dirname)) { + ETHASH_CRITICAL("Could not create the ethash directory"); + goto end; + } + + ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name); + char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name)); + if (!tmpfile) { + ETHASH_CRITICAL("Could not create the full DAG pathname"); + goto end; + } + + FILE *f; + if (!force_create) { + // try to open the file + f = ethash_fopen(tmpfile, "rb+"); + if (f) { + size_t found_size; + if (!ethash_file_size(f, &found_size)) { + fclose(f); + ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile); + goto free_memo; + } + if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) { + fclose(f); + ret = ETHASH_IO_MEMO_SIZE_MISMATCH; + goto free_memo; + } + // compare the magic number, no need to care about endianess since it's local + uint64_t magic_num; + if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { + // I/O error + fclose(f); + ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile); + ret = ETHASH_IO_MEMO_SIZE_MISMATCH; + goto free_memo; + } + if (magic_num != ETHASH_DAG_MAGIC_NUM) { + fclose(f); + ret = ETHASH_IO_MEMO_SIZE_MISMATCH; + goto free_memo; + } + ret = ETHASH_IO_MEMO_MATCH; + goto set_file; + } + } + + // file does not exist, will need to be created + f = ethash_fopen(tmpfile, "wb+"); + if (!f) { + ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile); + goto free_memo; + } + // make sure it's of the proper size + if (ethash_fseek(f, file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1, SEEK_SET) != 0) { + fclose(f); + ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fputc('\n', f) == EOF) { + fclose(f); + ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fflush(f) != 0) { + fclose(f); + ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + ret = ETHASH_IO_MEMO_MISMATCH; + goto set_file; + + ret = ETHASH_IO_MEMO_MATCH; +set_file: + *output_file = f; +free_memo: + free(tmpfile); +end: + return ret; +} diff --git a/src/Native/libetchash/io.h b/src/Native/libetchash/io.h new file mode 100644 index 000000000..45e7a74ab --- /dev/null +++ b/src/Native/libetchash/io.h @@ -0,0 +1,212 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file io.h + * @author Lefteris Karapetsas + * @date 2015 + */ +#pragma once +#include +#include +#include +#include +#ifdef __cplusplus +#define __STDC_FORMAT_MACROS 1 +#endif +#include +#include "endian.h" +#include "ethash.h" + +#ifdef __cplusplus +extern "C" { +#endif +// Maximum size for mutable part of DAG file name +// 6 is for "full-R", the suffix of the filename +// 10 is for maximum number of digits of a uint32_t (for REVISION) +// 1 is for - and 16 is for the first 16 hex digits for first 8 bytes of +// the seedhash and last 1 is for the null terminating character +// Reference: https://github.com/ethereum/wiki/wiki/Ethash-DAG +#define DAG_MUTABLE_NAME_MAX_SIZE (6 + 10 + 1 + 16 + 1) +/// Possible return values of @see ethash_io_prepare +enum ethash_io_rc { + ETHASH_IO_FAIL = 0, ///< There has been an IO failure + ETHASH_IO_MEMO_SIZE_MISMATCH, ///< DAG with revision/hash match, but file size was wrong. + ETHASH_IO_MEMO_MISMATCH, ///< The DAG file did not exist or there was revision/hash mismatch + ETHASH_IO_MEMO_MATCH, ///< DAG file existed and revision/hash matched. No need to do anything +}; + +// small hack for windows. I don't feel I should use va_args and forward just +// to have this one function properly cross-platform abstracted +#if defined(_WIN32) && !defined(__GNUC__) +#define snprintf(...) sprintf_s(__VA_ARGS__) +#endif + +/** + * Logs a critical error in important parts of ethash. Should mostly help + * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL + * ethash_full_t + */ +#ifdef ETHASH_PRINT_CRITICAL_OUTPUT +#define ETHASH_CRITICAL(...) \ + do \ + { \ + printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define ETHASH_CRITICAL(...) +#endif + + /** + * An fseek wrapper for crossplatform 64-bit seek. + * + * @param f The file stream whose fd to get + * @param offset Number of bytes from @a origin + * @param origin Initial position + * @return Current offset or -1 to indicate an error + */ +int ethash_fseek(FILE* f, size_t offset, int origin); + +/** + * Prepares io for ethash + * + * Create the DAG directory and the DAG file if they don't exist. + * + * @param[in] dirname A null terminated c-string of the path of the ethash + * data directory. If it does not exist it's created. + * @param[in] seedhash The seedhash of the current block number, used in the + * naming of the file as can be seen from the spec at: + * https://github.com/ethereum/wiki/wiki/Ethash-DAG + * @param[out] output_file If there was no failure then this will point to an open + * file descriptor. User is responsible for closing it. + * In the case of memo match then the file is open on read + * mode, while on the case of mismatch a new file is created + * on write mode + * @param[in] file_size The size that the DAG file should have on disk + * @param[out] force_create If true then there is no check to see if the file + * already exists + * @return For possible return values @see enum ethash_io_rc + */ +enum ethash_io_rc ethash_io_prepare( + char const* dirname, + ethash_h256_t const seedhash, + FILE** output_file, + uint64_t file_size, + bool force_create +); + +/** + * An fopen wrapper for no-warnings crossplatform fopen. + * + * Msvc compiler considers fopen to be insecure and suggests to use their + * alternative. This is a wrapper for this alternative. Another way is to + * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does + * not sound like a good idea. + * + * @param file_name The path to the file to open + * @param mode Opening mode. Check fopen() + * @return The FILE* or NULL in failure + */ +FILE* ethash_fopen(char const* file_name, char const* mode); + +/** + * An strncat wrapper for no-warnings crossplatform strncat. + * + * Msvc compiler considers strncat to be insecure and suggests to use their + * alternative. This is a wrapper for this alternative. Another way is to + * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does + * not sound like a good idea. + * + * @param des Destination buffer + * @param dest_size Maximum size of the destination buffer. This is the + * extra argument for the MSVC secure strncat + * @param src Souce buffer + * @param count Number of bytes to copy from source + * @return If all is well returns the dest buffer. If there is an + * error returns NULL + */ +char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count); + +/** + * A cross-platform mkdir wrapper to create a directory or assert it's there + * + * @param dirname The full path of the directory to create + * @return true if the directory was created or if it already + * existed + */ +bool ethash_mkdir(char const* dirname); + +/** + * Get a file's size + * + * @param[in] f The open file stream whose size to get + * @param[out] size Pass a size_t by reference to contain the file size + * @return true in success and false if there was a failure + */ +bool ethash_file_size(FILE* f, size_t* ret_size); + +/** + * Get a file descriptor number from a FILE stream + * + * @param f The file stream whose fd to get + * @return Platform specific fd handler + */ +int ethash_fileno(FILE* f); + +/** + * Create the filename for the DAG. + * + * @param dirname The directory name in which the DAG file should reside + * If it does not end with a directory separator it is appended. + * @param filename The actual name of the file + * @param filename_length The length of the filename in bytes + * @return A char* containing the full name. User must deallocate. + */ +char* ethash_io_create_filename( + char const* dirname, + char const* filename, + size_t filename_length +); + +/** + * Gets the default directory name for the DAG depending on the system + * + * The spec defining this directory is here: https://github.com/ethereum/wiki/wiki/Ethash-DAG + * + * @param[out] strbuf A string buffer of sufficient size to keep the + * null termninated string of the directory name + * @param[in] buffsize Size of @a strbuf in bytes + * @return true for success and false otherwise + */ +bool ethash_get_default_dirname(char* strbuf, size_t buffsize); + +static inline bool ethash_io_mutable_name( + uint32_t revision, + ethash_h256_t const* seed_hash, + char* output +) +{ + uint64_t hash = *((uint64_t*)seed_hash); +#if LITTLE_ENDIAN == BYTE_ORDER + hash = ethash_swap_u64(hash); +#endif + return snprintf(output, DAG_MUTABLE_NAME_MAX_SIZE, "full-R%u-%016" PRIx64, revision, hash) >= 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libetchash/io_posix.c b/src/Native/libetchash/io_posix.c new file mode 100644 index 000000000..b39ccec32 --- /dev/null +++ b/src/Native/libetchash/io_posix.c @@ -0,0 +1,111 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file io_posix.c + * @author Lefteris Karapetsas + * @date 2015 + */ + +#include "io.h" +#include +#include +#include +#include +#include +#include +#include +#include + +FILE* ethash_fopen(char const* file_name, char const* mode) +{ + return fopen(file_name, mode); +} + +char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count) +{ + return strlen(dest) + count + 1 <= dest_size ? strncat(dest, src, count) : NULL; +} + +bool ethash_mkdir(char const* dirname) +{ + int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + return rc != -1 || errno == EEXIST; +} + +int ethash_fileno(FILE *f) +{ + return fileno(f); +} + +char* ethash_io_create_filename( + char const* dirname, + char const* filename, + size_t filename_length +) +{ + size_t dirlen = strlen(dirname); + size_t dest_size = dirlen + filename_length + 1; + if (dirname[dirlen] != '/') { + dest_size += 1; + } + char* name = malloc(dest_size); + if (!name) { + return NULL; + } + + name[0] = '\0'; + ethash_strncat(name, dest_size, dirname, dirlen); + if (dirname[dirlen] != '/') { + ethash_strncat(name, dest_size, "/", 1); + } + ethash_strncat(name, dest_size, filename, filename_length); + return name; +} + +bool ethash_file_size(FILE* f, size_t* ret_size) +{ + struct stat st; + int fd; + if ((fd = fileno(f)) == -1 || fstat(fd, &st) != 0) { + return false; + } + *ret_size = st.st_size; + return true; +} + +bool ethash_get_default_dirname(char* strbuf, size_t buffsize) +{ + static const char dir_suffix[] = ".etchash/"; + strbuf[0] = '\0'; + char* home_dir = getenv("HOME"); + if (!home_dir || strlen(home_dir) == 0) + { + struct passwd* pwd = getpwuid(getuid()); + if (pwd) + home_dir = pwd->pw_dir; + } + + size_t len = strlen(home_dir); + if (!ethash_strncat(strbuf, buffsize, home_dir, len)) { + return false; + } + if (home_dir[len] != '/') { + if (!ethash_strncat(strbuf, buffsize, "/", 1)) { + return false; + } + } + return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix)); +} diff --git a/src/Native/libetchash/io_win32.c b/src/Native/libetchash/io_win32.c new file mode 100644 index 000000000..4827b9dbe --- /dev/null +++ b/src/Native/libetchash/io_win32.c @@ -0,0 +1,110 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file io_win32.c + * @author Lefteris Karapetsas + * @date 2015 + */ + +#include "io.h" +#include +#include +#include +#include +#include +#include + +FILE* ethash_fopen(char const* file_name, char const* mode) +{ + FILE* f; + return fopen_s(&f, file_name, mode) == 0 ? f : NULL; +} + +char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count) +{ + return strncat_s(dest, dest_size, src, count) == 0 ? dest : NULL; +} + +bool ethash_mkdir(char const* dirname) +{ + int rc = _mkdir(dirname); + return rc != -1 || errno == EEXIST; +} + +int ethash_fileno(FILE* f) +{ + return _fileno(f); +} + +char* ethash_io_create_filename( + char const* dirname, + char const* filename, + size_t filename_length +) +{ + size_t dirlen = strlen(dirname); + size_t dest_size = dirlen + filename_length + 1; + if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') { + dest_size += 1; + } + char* name = malloc(dest_size); + if (!name) { + return NULL; + } + + name[0] = '\0'; + ethash_strncat(name, dest_size, dirname, dirlen); + if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') { + ethash_strncat(name, dest_size, "\\", 1); + } + ethash_strncat(name, dest_size, filename, filename_length); + return name; +} + +bool ethash_file_size(FILE* f, size_t* ret_size) +{ +#ifdef _WIN32 + struct _stat64 st; + int fd; + if ((fd = _fileno(f)) == -1 || _fstat64(fd, &st) != 0) { + return false; + } + *ret_size = st.st_size; + return true; +#else + struct _stat st; + int fd; + if ((fd = _fileno(f)) == -1 || _fstat(fd, &st) != 0) { + return false; + } + *ret_size = st.st_size; + return true; +#endif +} + +bool ethash_get_default_dirname(char* strbuf, size_t buffsize) +{ + static const char dir_suffix[] = "Ethash\\"; + strbuf[0] = '\0'; + if (!SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, (CHAR*)strbuf))) { + return false; + } + if (!ethash_strncat(strbuf, buffsize, "\\", 1)) { + return false; + } + + return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix)); +} diff --git a/src/Native/libetchash/libetchash.sln b/src/Native/libetchash/libetchash.sln new file mode 100644 index 000000000..3490adb5f --- /dev/null +++ b/src/Native/libetchash/libetchash.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31229.75 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmultihash", "libetchash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Debug|x64.ActiveCfg = Debug|x64 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Debug|x64.Build.0 = Debug|x64 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Debug|x86.ActiveCfg = Debug|Win32 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Debug|x86.Build.0 = Debug|Win32 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Release|x64.ActiveCfg = Release|x64 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Release|x64.Build.0 = Release|x64 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Release|x86.ActiveCfg = Release|Win32 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libetchash/libetchash.vcxproj b/src/Native/libetchash/libetchash.vcxproj new file mode 100644 index 000000000..160fd6567 --- /dev/null +++ b/src/Native/libetchash/libetchash.vcxproj @@ -0,0 +1,202 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} + Win32Proj + netmultihashnative + 10.0 + libetchash + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)..\libethhash\windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Native/libetchash/mmap.h b/src/Native/libetchash/mmap.h new file mode 100644 index 000000000..1e226e83f --- /dev/null +++ b/src/Native/libetchash/mmap.h @@ -0,0 +1,47 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file mmap.h + * @author Lefteris Karapetsas + * @date 2015 + */ +#pragma once +#if defined(__MINGW32__) || defined(_WIN32) +#include + +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +/* This flag is only available in WinXP+ */ +#ifdef FILE_MAP_EXECUTE +#define PROT_EXEC 0x4 +#else +#define PROT_EXEC 0x0 +#define FILE_MAP_EXECUTE 0 +#endif + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_ANONYMOUS 0x20 +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FAILED ((void *) -1) + +void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset); +void munmap(void* addr, size_t length); +#else // posix, yay! ^_^ +#include +#endif + + diff --git a/src/Native/libetchash/mmap_win32.c b/src/Native/libetchash/mmap_win32.c new file mode 100644 index 000000000..293de90fb --- /dev/null +++ b/src/Native/libetchash/mmap_win32.c @@ -0,0 +1,84 @@ +/* mmap() replacement for Windows + * + * Author: Mike Frysinger + * Placed into the public domain + */ + +/* References: + * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx + * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx + * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx + * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx + */ + +#include +#include +#include "mmap.h" + +#ifdef __USE_FILE_OFFSET64 +# define DWORD_HI(x) (x >> 32) +# define DWORD_LO(x) ((x) & 0xffffffff) +#else +# define DWORD_HI(x) (0) +# define DWORD_LO(x) (x) +#endif + +void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset) +{ + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return MAP_FAILED; + if (fd == -1) { + if (!(flags & MAP_ANON) || offset) + return MAP_FAILED; + } else if (flags & MAP_ANON) + return MAP_FAILED; + + DWORD flProtect; + if (prot & PROT_WRITE) { + if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE_READWRITE; + else + flProtect = PAGE_READWRITE; + } else if (prot & PROT_EXEC) { + if (prot & PROT_READ) + flProtect = PAGE_EXECUTE_READ; + else if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE; + } else + flProtect = PAGE_READONLY; + + off_t end = length + offset; + HANDLE mmap_fd, h; + if (fd == -1) + mmap_fd = INVALID_HANDLE_VALUE; + else + mmap_fd = (HANDLE)_get_osfhandle(fd); + h = CreateFileMapping(mmap_fd, NULL, flProtect, 0, 0, NULL); + if (h == NULL) + return MAP_FAILED; + + DWORD dwDesiredAccess; + if (prot & PROT_WRITE) + dwDesiredAccess = FILE_MAP_WRITE; + else + dwDesiredAccess = FILE_MAP_READ; + if (prot & PROT_EXEC) + dwDesiredAccess |= FILE_MAP_EXECUTE; + if (flags & MAP_PRIVATE) + dwDesiredAccess |= FILE_MAP_COPY; + void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length); + if (ret == NULL) { + ret = MAP_FAILED; + } + // since we are handling the file ourselves with fd, close the Windows Handle here + CloseHandle(h); + return ret; +} + +void munmap(void* addr, size_t length) +{ + UnmapViewOfFile(addr); +} + +#undef DWORD_HI +#undef DWORD_LO diff --git a/src/Native/libetchash/sha3.c b/src/Native/libetchash/sha3.c new file mode 100644 index 000000000..e72fe1018 --- /dev/null +++ b/src/Native/libetchash/sha3.c @@ -0,0 +1,151 @@ +/** libkeccak-tiny +* +* A single-file implementation of SHA-3 and SHAKE. +* +* Implementor: David Leon Gil +* License: CC0, attribution kindly requested. Blame taken too, +* but not liability. +*/ +#include "sha3.h" + +#include +#include +#include +#include + +/******** The Keccak-f[1600] permutation ********/ + +/*** Constants. ***/ +static const uint8_t rho[24] = \ + { 1, 3, 6, 10, 15, 21, + 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, + 62, 18, 39, 61, 20, 44}; +static const uint8_t pi[24] = \ + {10, 7, 11, 17, 18, 3, + 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, + 20, 14, 22, 9, 6, 1}; +static const uint64_t RC[24] = \ + {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, + 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, + 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; + +/*** Helper macros to unroll the permutation. ***/ +#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) +#define REPEAT6(e) e e e e e e +#define REPEAT24(e) REPEAT6(e e e e) +#define REPEAT5(e) e e e e e +#define FOR5(v, s, e) \ + v = 0; \ + REPEAT5(e; v += s;) + +/*** Keccak-f[1600] ***/ +static inline void keccakf(void* state) { + uint64_t* a = (uint64_t*)state; + uint64_t b[5] = {0}; + uint64_t t = 0; + uint8_t x, y; + + for (int i = 0; i < 24; i++) { + // Theta + FOR5(x, 1, + b[x] = 0; + FOR5(y, 5, + b[x] ^= a[x + y]; )) + FOR5(x, 1, + FOR5(y, 5, + a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) + // Rho and pi + t = a[1]; + x = 0; + REPEAT24(b[0] = a[pi[x]]; + a[pi[x]] = rol(t, rho[x]); + t = b[0]; + x++; ) + // Chi + FOR5(y, + 5, + FOR5(x, 1, + b[x] = a[y + x];) + FOR5(x, 1, + a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) + // Iota + a[0] ^= RC[i]; + } +} + +/******** The FIPS202-defined functions. ********/ + +/*** Some helper macros. ***/ + +#define _(S) do { S } while (0) +#define FOR(i, ST, L, S) \ + _(for (size_t i = 0; i < L; i += ST) { S; }) +#define mkapply_ds(NAME, S) \ + static inline void NAME(uint8_t* dst, \ + const uint8_t* src, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } +#define mkapply_sd(NAME, S) \ + static inline void NAME(const uint8_t* src, \ + uint8_t* dst, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } + +mkapply_ds(xorin, dst[i] ^= src[i]) // xorin +mkapply_sd(setout, dst[i] = src[i]) // setout + +#define P keccakf +#define Plen 200 + +// Fold P*F over the full blocks of an input. +#define foldP(I, L, F) \ + while (L >= rate) { \ + F(a, I, rate); \ + P(a); \ + I += rate; \ + L -= rate; \ + } + +/** The sponge-based hash construction. **/ +static inline int hash(uint8_t* out, size_t outlen, + const uint8_t* in, size_t inlen, + size_t rate, uint8_t delim) { + if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { + return -1; + } + uint8_t a[Plen] = {0}; + // Absorb input. + foldP(in, inlen, xorin); + // Xor in the DS and pad frame. + a[inlen] ^= delim; + a[rate - 1] ^= 0x80; + // Xor in the last block. + xorin(a, in, inlen); + // Apply P + P(a); + // Squeeze output. + foldP(out, outlen, setout); + setout(a, out, outlen); + memset(a, 0, 200); + return 0; +} + +#define defsha3(bits) \ + int sha3_##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + if (outlen > (bits/8)) { \ + return -1; \ + } \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ + } + +/*** FIPS202 SHA3 FOFs ***/ +defsha3(256) +defsha3(512) diff --git a/src/Native/libetchash/sha3.h b/src/Native/libetchash/sha3.h new file mode 100644 index 000000000..a38006292 --- /dev/null +++ b/src/Native/libetchash/sha3.h @@ -0,0 +1,31 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "compiler.h" +#include +#include + +struct ethash_h256; + +#define decsha3(bits) \ + int sha3_##bits(uint8_t*, size_t, uint8_t const*, size_t); + +decsha3(256) +decsha3(512) + +static inline void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t const size) +{ + sha3_256((uint8_t*)ret, 32, data, size); +} + +static inline void SHA3_512(uint8_t* ret, uint8_t const* data, size_t const size) +{ + sha3_512(ret, 64, data, size); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libetchash/sha3_cryptopp.cpp b/src/Native/libetchash/sha3_cryptopp.cpp new file mode 100644 index 000000000..519d1405e --- /dev/null +++ b/src/Native/libetchash/sha3_cryptopp.cpp @@ -0,0 +1,37 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ + +/** @file sha3.cpp +* @author Tim Hughes +* @date 2015 +*/ +#include +#include + +extern "C" { +struct ethash_h256; +typedef struct ethash_h256 ethash_h256_t; +void SHA3_256(ethash_h256_t const* ret, uint8_t const* data, size_t size) +{ + CryptoPP::SHA3_256().CalculateDigest((uint8_t*)ret, data, size); +} + +void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size) +{ + CryptoPP::SHA3_512().CalculateDigest(ret, data, size); +} +} diff --git a/src/Native/libetchash/sha3_cryptopp.h b/src/Native/libetchash/sha3_cryptopp.h new file mode 100644 index 000000000..9edc407d5 --- /dev/null +++ b/src/Native/libetchash/sha3_cryptopp.h @@ -0,0 +1,18 @@ +#pragma once + +#include "compiler.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ethash_h256; + +void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t size); +void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size); + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libetchash/stdafx.cpp b/src/Native/libetchash/stdafx.cpp new file mode 100644 index 000000000..bd27597c6 --- /dev/null +++ b/src/Native/libetchash/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// $safeprojectname$.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/src/Native/libetchash/stdafx.h b/src/Native/libetchash/stdafx.h new file mode 100644 index 000000000..f3a07375c --- /dev/null +++ b/src/Native/libetchash/stdafx.h @@ -0,0 +1,16 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + + + +// TODO: reference additional headers your program requires here diff --git a/src/Native/libetchash/stdint.h b/src/Native/libetchash/stdint.h new file mode 100644 index 000000000..4fe0ef9a9 --- /dev/null +++ b/src/Native/libetchash/stdint.h @@ -0,0 +1,259 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if _MSC_VER >= 1600 // [ +#include +#else // ] _MSC_VER >= 1600 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] diff --git a/src/Native/libetchash/targetver.h b/src/Native/libetchash/targetver.h new file mode 100644 index 000000000..87c0086de --- /dev/null +++ b/src/Native/libetchash/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/src/Native/libetchash/util.h b/src/Native/libetchash/util.h new file mode 100644 index 000000000..c5fc6e55b --- /dev/null +++ b/src/Native/libetchash/util.h @@ -0,0 +1,47 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file util.h + * @author Tim Hughes + * @date 2015 + */ +#pragma once +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +void debugf(char const* str, ...); +#else +#define debugf printf +#endif + +static inline uint32_t min_u32(uint32_t a, uint32_t b) +{ + return a < b ? a : b; +} + +static inline uint32_t clamp_u32(uint32_t x, uint32_t min_, uint32_t max_) +{ + return x < min_ ? min_ : (x > max_ ? max_ : x); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libetchash/util_win32.c b/src/Native/libetchash/util_win32.c new file mode 100644 index 000000000..268e6db05 --- /dev/null +++ b/src/Native/libetchash/util_win32.c @@ -0,0 +1,38 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: 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. + + cpp-ethereum 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. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file util.c + * @author Tim Hughes + * @date 2015 + */ +#include +#include +#include "util.h" + + +// foward declare without all of Windows.h +__declspec(dllimport) void __stdcall OutputDebugStringA(char const* lpOutputString); + +void debugf(char const* str, ...) +{ + va_list args; + va_start(args, str); + + char buf[1<<16]; + _vsnprintf_s(buf, sizeof(buf), sizeof(buf), str, args); + buf[sizeof(buf)-1] = '\0'; + OutputDebugStringA(buf); +} diff --git a/src/Native/libubqhash/Makefile b/src/Native/libubqhash/Makefile new file mode 100644 index 000000000..b76381c8b --- /dev/null +++ b/src/Native/libubqhash/Makefile @@ -0,0 +1,16 @@ +CFLAGS += -g -Wall -c -fPIC -O2 -Wno-pointer-sign -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-discarded-qualifiers -Wno-unused-const-variable $(CPU_FLAGS) $(HAVE_FEATURE) +CXXFLAGS += -g -Wall -fPIC -fpermissive -O2 -Wno-char-subscripts -Wno-unused-variable -Wno-unused-function -Wno-strict-aliasing -Wno-sign-compare -std=c++11 $(CPU_FLAGS) $(HAVE_FEATURE) +LDFLAGS += -shared +TARGET = libubqhash.so + +OBJECTS = internal.o io.o io_posix.o sha3.o exports.o blake2.o + +all: $(TARGET) + +$(TARGET): $(OBJECTS) + $(CXX) $(LDFLAGS) -o $@ $^ $(LDLIBS) + +.PHONY: clean + +clean: + $(RM) $(TARGET) $(OBJECTS) diff --git a/src/Native/libubqhash/blake2-impl.h b/src/Native/libubqhash/blake2-impl.h new file mode 100644 index 000000000..5dff7fc7a --- /dev/null +++ b/src/Native/libubqhash/blake2-impl.h @@ -0,0 +1,160 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2_IMPL_H +#define BLAKE2_IMPL_H + +#include +#include + +#if !defined(__cplusplus) && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 199901L) + #if defined(_MSC_VER) + #define BLAKE2_INLINE __inline + #elif defined(__GNUC__) + #define BLAKE2_INLINE __inline__ + #else + #define BLAKE2_INLINE + #endif +#else + #define BLAKE2_INLINE inline +#endif + +static BLAKE2_INLINE uint32_t load32( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint32_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint32_t )( p[0] ) << 0) | + (( uint32_t )( p[1] ) << 8) | + (( uint32_t )( p[2] ) << 16) | + (( uint32_t )( p[3] ) << 24) ; +#endif +} + +static BLAKE2_INLINE uint64_t load64( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint64_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint64_t )( p[0] ) << 0) | + (( uint64_t )( p[1] ) << 8) | + (( uint64_t )( p[2] ) << 16) | + (( uint64_t )( p[3] ) << 24) | + (( uint64_t )( p[4] ) << 32) | + (( uint64_t )( p[5] ) << 40) | + (( uint64_t )( p[6] ) << 48) | + (( uint64_t )( p[7] ) << 56) ; +#endif +} + +static BLAKE2_INLINE uint16_t load16( const void *src ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + uint16_t w; + memcpy(&w, src, sizeof w); + return w; +#else + const uint8_t *p = ( const uint8_t * )src; + return (( uint16_t )( p[0] ) << 0) | + (( uint16_t )( p[1] ) << 8) ; +#endif +} + +static BLAKE2_INLINE void store16( void *dst, uint16_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + *p++ = ( uint8_t )w; w >>= 8; + *p++ = ( uint8_t )w; +#endif +} + +static BLAKE2_INLINE void store32( void *dst, uint32_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); +#endif +} + +static BLAKE2_INLINE void store64( void *dst, uint64_t w ) +{ +#if defined(NATIVE_LITTLE_ENDIAN) + memcpy(dst, &w, sizeof w); +#else + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); + p[4] = (uint8_t)(w >> 32); + p[5] = (uint8_t)(w >> 40); + p[6] = (uint8_t)(w >> 48); + p[7] = (uint8_t)(w >> 56); +#endif +} + +static BLAKE2_INLINE uint64_t load48( const void *src ) +{ + const uint8_t *p = ( const uint8_t * )src; + return (( uint64_t )( p[0] ) << 0) | + (( uint64_t )( p[1] ) << 8) | + (( uint64_t )( p[2] ) << 16) | + (( uint64_t )( p[3] ) << 24) | + (( uint64_t )( p[4] ) << 32) | + (( uint64_t )( p[5] ) << 40) ; +} + +static BLAKE2_INLINE void store48( void *dst, uint64_t w ) +{ + uint8_t *p = ( uint8_t * )dst; + p[0] = (uint8_t)(w >> 0); + p[1] = (uint8_t)(w >> 8); + p[2] = (uint8_t)(w >> 16); + p[3] = (uint8_t)(w >> 24); + p[4] = (uint8_t)(w >> 32); + p[5] = (uint8_t)(w >> 40); +} + +static BLAKE2_INLINE uint32_t rotr32( const uint32_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 32 - c ) ); +} + +static BLAKE2_INLINE uint64_t rotr64( const uint64_t w, const unsigned c ) +{ + return ( w >> c ) | ( w << ( 64 - c ) ); +} + +/* prevents compiler optimizing out memset() */ +static BLAKE2_INLINE void secure_zero_memory(void *v, size_t n) +{ + static void *(*const volatile memset_v)(void *, int, size_t) = &memset; + memset_v(v, 0, n); +} + +#endif diff --git a/src/Native/libubqhash/blake2.c b/src/Native/libubqhash/blake2.c new file mode 100644 index 000000000..cd38b1ba0 --- /dev/null +++ b/src/Native/libubqhash/blake2.c @@ -0,0 +1,379 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ + +#include +#include +#include + +#include "blake2.h" +#include "blake2-impl.h" + +static const uint64_t blake2b_IV[8] = +{ + 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL, + 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL, + 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL, + 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL +}; + +static const uint8_t blake2b_sigma[12][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } +}; + + +static void blake2b_set_lastnode( blake2b_state *S ) +{ + S->f[1] = (uint64_t)-1; +} + +/* Some helper functions, not necessarily useful */ +static int blake2b_is_lastblock( const blake2b_state *S ) +{ + return S->f[0] != 0; +} + +static void blake2b_set_lastblock( blake2b_state *S ) +{ + if( S->last_node ) blake2b_set_lastnode( S ); + + S->f[0] = (uint64_t)-1; +} + +static void blake2b_increment_counter( blake2b_state *S, const uint64_t inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + +static void blake2b_init0( blake2b_state *S ) +{ + size_t i; + memset( S, 0, sizeof( blake2b_state ) ); + + for( i = 0; i < 8; ++i ) S->h[i] = blake2b_IV[i]; +} + +/* init xors IV with input parameter block */ +int blake2b_init_param( blake2b_state *S, const blake2b_param *P ) +{ + const uint8_t *p = ( const uint8_t * )( P ); + size_t i; + + blake2b_init0( S ); + + /* IV XOR ParamBlock */ + for( i = 0; i < 8; ++i ) + S->h[i] ^= load64( p + sizeof( S->h[i] ) * i ); + + S->outlen = P->digest_length; + return 0; +} + + + +int blake2b_init( blake2b_state *S, size_t outlen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = 0; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + return blake2b_init_param( S, P ); +} + + +int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ) +{ + blake2b_param P[1]; + + if ( ( !outlen ) || ( outlen > BLAKE2B_OUTBYTES ) ) return -1; + + if ( !key || !keylen || keylen > BLAKE2B_KEYBYTES ) return -1; + + P->digest_length = (uint8_t)outlen; + P->key_length = (uint8_t)keylen; + P->fanout = 1; + P->depth = 1; + store32( &P->leaf_length, 0 ); + store32( &P->node_offset, 0 ); + store32( &P->xof_length, 0 ); + P->node_depth = 0; + P->inner_length = 0; + memset( P->reserved, 0, sizeof( P->reserved ) ); + memset( P->salt, 0, sizeof( P->salt ) ); + memset( P->personal, 0, sizeof( P->personal ) ); + + if( blake2b_init_param( S, P ) < 0 ) return -1; + + { + uint8_t block[BLAKE2B_BLOCKBYTES]; + memset( block, 0, BLAKE2B_BLOCKBYTES ); + memcpy( block, key, keylen ); + blake2b_update( S, block, BLAKE2B_BLOCKBYTES ); + secure_zero_memory( block, BLAKE2B_BLOCKBYTES ); /* Burn the key from stack */ + } + return 0; +} + +#define G(r,i,a,b,c,d) \ + do { \ + a = a + b + m[blake2b_sigma[r][2*i+0]]; \ + d = rotr64(d ^ a, 32); \ + c = c + d; \ + b = rotr64(b ^ c, 24); \ + a = a + b + m[blake2b_sigma[r][2*i+1]]; \ + d = rotr64(d ^ a, 16); \ + c = c + d; \ + b = rotr64(b ^ c, 63); \ + } while(0) + +#define ROUND(r) \ + do { \ + G(r,0,v[ 0],v[ 4],v[ 8],v[12]); \ + G(r,1,v[ 1],v[ 5],v[ 9],v[13]); \ + G(r,2,v[ 2],v[ 6],v[10],v[14]); \ + G(r,3,v[ 3],v[ 7],v[11],v[15]); \ + G(r,4,v[ 0],v[ 5],v[10],v[15]); \ + G(r,5,v[ 1],v[ 6],v[11],v[12]); \ + G(r,6,v[ 2],v[ 7],v[ 8],v[13]); \ + G(r,7,v[ 3],v[ 4],v[ 9],v[14]); \ + } while(0) + +static void blake2b_compress( blake2b_state *S, const uint8_t block[BLAKE2B_BLOCKBYTES] ) +{ + uint64_t m[16]; + uint64_t v[16]; + size_t i; + + for( i = 0; i < 16; ++i ) { + m[i] = load64( block + i * sizeof( m[i] ) ); + } + + for( i = 0; i < 8; ++i ) { + v[i] = S->h[i]; + } + + v[ 8] = blake2b_IV[0]; + v[ 9] = blake2b_IV[1]; + v[10] = blake2b_IV[2]; + v[11] = blake2b_IV[3]; + v[12] = blake2b_IV[4] ^ S->t[0]; + v[13] = blake2b_IV[5] ^ S->t[1]; + v[14] = blake2b_IV[6] ^ S->f[0]; + v[15] = blake2b_IV[7] ^ S->f[1]; + + ROUND( 0 ); + ROUND( 1 ); + ROUND( 2 ); + ROUND( 3 ); + ROUND( 4 ); + ROUND( 5 ); + ROUND( 6 ); + ROUND( 7 ); + ROUND( 8 ); + ROUND( 9 ); + ROUND( 10 ); + ROUND( 11 ); + + for( i = 0; i < 8; ++i ) { + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; + } +} + +#undef G +#undef ROUND + +int blake2b_update( blake2b_state *S, const void *pin, size_t inlen ) +{ + const unsigned char * in = (const unsigned char *)pin; + if( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = BLAKE2B_BLOCKBYTES - left; + if( inlen > fill ) + { + S->buflen = 0; + memcpy( S->buf + left, in, fill ); /* Fill buffer */ + blake2b_increment_counter( S, BLAKE2B_BLOCKBYTES ); + blake2b_compress( S, S->buf ); /* Compress */ + in += fill; inlen -= fill; + while(inlen > BLAKE2B_BLOCKBYTES) { + blake2b_increment_counter(S, BLAKE2B_BLOCKBYTES); + blake2b_compress( S, in ); + in += BLAKE2B_BLOCKBYTES; + inlen -= BLAKE2B_BLOCKBYTES; + } + } + memcpy( S->buf + S->buflen, in, inlen ); + S->buflen += inlen; + } + return 0; +} + +int blake2b_final( blake2b_state *S, void *out, size_t outlen ) +{ + uint8_t buffer[BLAKE2B_OUTBYTES] = {0}; + size_t i; + + if( out == NULL || outlen < S->outlen ) + return -1; + + if( blake2b_is_lastblock( S ) ) + return -1; + + blake2b_increment_counter( S, S->buflen ); + blake2b_set_lastblock( S ); + memset( S->buf + S->buflen, 0, BLAKE2B_BLOCKBYTES - S->buflen ); /* Padding */ + blake2b_compress( S, S->buf ); + + for( i = 0; i < 8; ++i ) /* Output full hash to temp buffer */ + store64( buffer + sizeof( S->h[i] ) * i, S->h[i] ); + + memcpy( out, buffer, S->outlen ); + secure_zero_memory(buffer, sizeof(buffer)); + return 0; +} + +/* inlen, at least, should be uint64_t. Others can be size_t. */ +int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) +{ + blake2b_state S[1]; + + /* Verify parameters */ + if ( NULL == in && inlen > 0 ) return -1; + + if ( NULL == out ) return -1; + + if( NULL == key && keylen > 0 ) return -1; + + if( !outlen || outlen > BLAKE2B_OUTBYTES ) return -1; + + if( keylen > BLAKE2B_KEYBYTES ) return -1; + + if( keylen > 0 ) + { + if( blake2b_init_key( S, outlen, key, keylen ) < 0 ) return -1; + } + else + { + if( blake2b_init( S, outlen ) < 0 ) return -1; + } + + blake2b_update( S, ( const uint8_t * )in, inlen ); + blake2b_final( S, out, outlen ); + return 0; +} + +int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ) { + return blake2b(out, outlen, in, inlen, key, keylen); +} + +#if defined(SUPERCOP) +int crypto_hash( unsigned char *out, unsigned char *in, unsigned long long inlen ) +{ + return blake2b( out, BLAKE2B_OUTBYTES, in, inlen, NULL, 0 ); +} +#endif + +#if defined(BLAKE2B_SELFTEST) +#include +#include "blake2-kat.h" +int main( void ) +{ + uint8_t key[BLAKE2B_KEYBYTES]; + uint8_t buf[BLAKE2_KAT_LENGTH]; + size_t i, step; + + for( i = 0; i < BLAKE2B_KEYBYTES; ++i ) + key[i] = ( uint8_t )i; + + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + buf[i] = ( uint8_t )i; + + /* Test simple API */ + for( i = 0; i < BLAKE2_KAT_LENGTH; ++i ) + { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2b( hash, BLAKE2B_OUTBYTES, buf, i, key, BLAKE2B_KEYBYTES ); + + if( 0 != memcmp( hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES ) ) + { + goto fail; + } + } + + /* Test streaming API */ + for(step = 1; step < BLAKE2B_BLOCKBYTES; ++step) { + for (i = 0; i < BLAKE2_KAT_LENGTH; ++i) { + uint8_t hash[BLAKE2B_OUTBYTES]; + blake2b_state S; + uint8_t * p = buf; + size_t mlen = i; + int err = 0; + + if( (err = blake2b_init_key(&S, BLAKE2B_OUTBYTES, key, BLAKE2B_KEYBYTES)) < 0 ) { + goto fail; + } + + while (mlen >= step) { + if ( (err = blake2b_update(&S, p, step)) < 0 ) { + goto fail; + } + mlen -= step; + p += step; + } + if ( (err = blake2b_update(&S, p, mlen)) < 0) { + goto fail; + } + if ( (err = blake2b_final(&S, hash, BLAKE2B_OUTBYTES)) < 0) { + goto fail; + } + + if (0 != memcmp(hash, blake2b_keyed_kat[i], BLAKE2B_OUTBYTES)) { + goto fail; + } + } + } + + puts( "ok" ); + return 0; +fail: + puts("error"); + return -1; +} +#endif diff --git a/src/Native/libubqhash/blake2.h b/src/Native/libubqhash/blake2.h new file mode 100644 index 000000000..2ba70501d --- /dev/null +++ b/src/Native/libubqhash/blake2.h @@ -0,0 +1,168 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Copyright 2012, Samuel Neves . You may use this under the + terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at + your option. The terms of these licenses can be found at: + + - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0 + - OpenSSL license : https://www.openssl.org/source/license.html + - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0 + + More information about the BLAKE2 hash function can be found at + https://blake2.net. +*/ +#ifndef BLAKE2_H +#define BLAKE2_H + +#include +#include + +#if defined(_MSC_VER) +#define BLAKE2_PACKED(x) __pragma(pack(push, 1)) x __pragma(pack(pop)) +#else +#define BLAKE2_PACKED(x) x __attribute__((packed)) +#endif + +#if defined(__cplusplus) +extern "C" { +#endif + +struct ethash_h256; + + enum blake2s_constant + { + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32, + BLAKE2S_KEYBYTES = 32, + BLAKE2S_SALTBYTES = 8, + BLAKE2S_PERSONALBYTES = 8 + }; + + enum blake2b_constant + { + BLAKE2B_BLOCKBYTES = 128, + BLAKE2B_OUTBYTES = 64, + BLAKE2B_KEYBYTES = 64, + BLAKE2B_SALTBYTES = 16, + BLAKE2B_PERSONALBYTES = 16 + }; + + typedef struct blake2s_state__ + { + uint32_t h[8]; + uint32_t t[2]; + uint32_t f[2]; + uint8_t buf[BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; + } blake2s_state; + + typedef struct blake2b_state__ + { + uint64_t h[8]; + uint64_t t[2]; + uint64_t f[2]; + uint8_t buf[BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + uint8_t last_node; + } blake2b_state; + + typedef struct blake2sp_state__ + { + blake2s_state S[8][1]; + blake2s_state R[1]; + uint8_t buf[8 * BLAKE2S_BLOCKBYTES]; + size_t buflen; + size_t outlen; + } blake2sp_state; + + typedef struct blake2bp_state__ + { + blake2b_state S[4][1]; + blake2b_state R[1]; + uint8_t buf[4 * BLAKE2B_BLOCKBYTES]; + size_t buflen; + size_t outlen; + } blake2bp_state; + + + BLAKE2_PACKED(struct blake2s_param__ + { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint16_t xof_length; /* 14 */ + uint8_t node_depth; /* 15 */ + uint8_t inner_length; /* 16 */ + /* uint8_t reserved[0]; */ + uint8_t salt[BLAKE2S_SALTBYTES]; /* 24 */ + uint8_t personal[BLAKE2S_PERSONALBYTES]; /* 32 */ + }); + + typedef struct blake2s_param__ blake2s_param; + + BLAKE2_PACKED(struct blake2b_param__ + { + uint8_t digest_length; /* 1 */ + uint8_t key_length; /* 2 */ + uint8_t fanout; /* 3 */ + uint8_t depth; /* 4 */ + uint32_t leaf_length; /* 8 */ + uint32_t node_offset; /* 12 */ + uint32_t xof_length; /* 16 */ + uint8_t node_depth; /* 17 */ + uint8_t inner_length; /* 18 */ + uint8_t reserved[14]; /* 32 */ + uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */ + uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */ + }); + + typedef struct blake2b_param__ blake2b_param; + + typedef struct blake2xs_state__ + { + blake2s_state S[1]; + blake2s_param P[1]; + } blake2xs_state; + + typedef struct blake2xb_state__ + { + blake2b_state S[1]; + blake2b_param P[1]; + } blake2xb_state; + + /* Padded structs result in a compile-time error */ + enum { + BLAKE2_DUMMY_1 = 1/(sizeof(blake2s_param) == BLAKE2S_OUTBYTES), + BLAKE2_DUMMY_2 = 1/(sizeof(blake2b_param) == BLAKE2B_OUTBYTES) + }; + + /* Streaming API */ + int blake2b_init( blake2b_state *S, size_t outlen ); + int blake2b_init_key( blake2b_state *S, size_t outlen, const void *key, size_t keylen ); + int blake2b_init_param( blake2b_state *S, const blake2b_param *P ); + int blake2b_update( blake2b_state *S, const void *in, size_t inlen ); + int blake2b_final( blake2b_state *S, void *out, size_t outlen ); + + /* Simple API */ + int blake2b( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + /* This is simply an alias for blake2b */ + int blake2( void *out, size_t outlen, const void *in, size_t inlen, const void *key, size_t keylen ); + + static inline void BLAKE2B_512(uint8_t* ret, uint8_t const* data, size_t const size) + { + blake2b(ret, 64, data, size, 0, 0 ); + } + +#if defined(__cplusplus) +} +#endif + +#endif diff --git a/src/Native/libubqhash/blake2_cryptopp.cpp b/src/Native/libubqhash/blake2_cryptopp.cpp new file mode 100644 index 000000000..dc50abcbb --- /dev/null +++ b/src/Native/libubqhash/blake2_cryptopp.cpp @@ -0,0 +1,32 @@ +/* + This file is part of ubqhash. + + ubqhash is free software: 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. + + ubqhash 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. + + You should have received a copy of the GNU General Public License + along with ubqhash. If not, see . +*/ + +/** @file sha3.cpp +* @author Tim Hughes +* @date 2015 +*/ +#include +#include + +extern "C" { +struct ethash_h256; +typedef struct ethash_h256 ethash_h256_t; +void BLAKE2B_512(uint8_t* const ret, uint8_t const* data, size_t size) +{ + CryptoPP::BLAKE2b().CalculateDigest(ret, data, size); +} +} diff --git a/src/Native/libubqhash/blake2_cryptopp.h b/src/Native/libubqhash/blake2_cryptopp.h new file mode 100644 index 000000000..3c14778c8 --- /dev/null +++ b/src/Native/libubqhash/blake2_cryptopp.h @@ -0,0 +1,17 @@ +#pragma once + +#include "compiler.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ethash_h256; + +void BLAKE2B_512(uint8_t* const ret, uint8_t const* data, size_t size); + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libubqhash/compiler.h b/src/Native/libubqhash/compiler.h new file mode 100644 index 000000000..40fc816d1 --- /dev/null +++ b/src/Native/libubqhash/compiler.h @@ -0,0 +1,32 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: 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. + + cpp-ethereum 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. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file compiler.h + * @date 2014 + */ +#pragma once + +// Visual Studio doesn't support the inline keyword in C mode +#if defined(_MSC_VER) && !defined(__cplusplus) +#define inline __inline +#endif + +// pretend restrict is a standard keyword +#if defined(_MSC_VER) +#define restrict +#else +#define restrict __restrict__ +#endif diff --git a/src/Native/libubqhash/data_sizes.h b/src/Native/libubqhash/data_sizes.h new file mode 100644 index 000000000..83cc30bcb --- /dev/null +++ b/src/Native/libubqhash/data_sizes.h @@ -0,0 +1,812 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software FoundationUUU,either version 3 of the LicenseUUU,or + (at your option) any later version. + + cpp-ethereum is distributed in the hope that it will be usefulU, + 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. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If notUUU,see . +*/ + +/** @file data_sizes.h +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +#pragma once + +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// 2048 Epochs (~20 years) worth of tabulated DAG sizes + +// Generated with the following Mathematica Code: + +// GetCacheSizes[n_] := Module[{ +// CacheSizeBytesInit = 2^24, +// CacheGrowth = 2^17, +// HashBytes = 64, +// j = 0}, +// Reap[ +// While[j < n, +// Module[{i = +// Floor[(CacheSizeBytesInit + CacheGrowth * j) / HashBytes]}, +// While[! PrimeQ[i], i--]; +// Sow[i*HashBytes]; j++]]]][[2]][[1]] + + +static const uint64_t dag_sizes[2048] = { + 1073739904U, 1082130304U, 1090514816U, 1098906752U, 1107293056U, + 1115684224U, 1124070016U, 1132461952U, 1140849536U, 1149232768U, + 1157627776U, 1166013824U, 1174404736U, 1182786944U, 1191180416U, + 1199568512U, 1207958912U, 1216345216U, 1224732032U, 1233124736U, + 1241513344U, 1249902464U, 1258290304U, 1266673792U, 1275067264U, + 1283453312U, 1291844992U, 1300234112U, 1308619904U, 1317010048U, + 1325397376U, 1333787776U, 1342176128U, 1350561664U, 1358954368U, + 1367339392U, 1375731584U, 1384118144U, 1392507008U, 1400897408U, + 1409284736U, 1417673344U, 1426062464U, 1434451072U, 1442839168U, + 1451229056U, 1459615616U, 1468006016U, 1476394112U, 1484782976U, + 1493171584U, 1501559168U, 1509948032U, 1518337664U, 1526726528U, + 1535114624U, 1543503488U, 1551892096U, 1560278656U, 1568669056U, + 1577056384U, 1585446272U, 1593831296U, 1602219392U, 1610610304U, + 1619000192U, 1627386752U, 1635773824U, 1644164224U, 1652555648U, + 1660943488U, 1669332608U, 1677721216U, 1686109312U, 1694497664U, + 1702886272U, 1711274624U, 1719661184U, 1728047744U, 1736434816U, + 1744829056U, 1753218944U, 1761606272U, 1769995904U, 1778382464U, + 1786772864U, 1795157888U, 1803550592U, 1811937664U, 1820327552U, + 1828711552U, 1837102976U, 1845488768U, 1853879936U, 1862269312U, + 1870656896U, 1879048064U, 1887431552U, 1895825024U, 1904212096U, + 1912601216U, 1920988544U, 1929379456U, 1937765504U, 1946156672U, + 1954543232U, 1962932096U, 1971321728U, 1979707264U, 1988093056U, + 1996487552U, 2004874624U, 2013262208U, 2021653888U, 2030039936U, + 2038430848U, 2046819968U, 2055208576U, 2063596672U, 2071981952U, + 2080373632U, 2088762752U, 2097149056U, 2105539712U, 2113928576U, + 2122315136U, 2130700672U, 2139092608U, 2147483264U, 2155872128U, + 2164257664U, 2172642176U, 2181035392U, 2189426048U, 2197814912U, + 2206203008U, 2214587264U, 2222979712U, 2231367808U, 2239758208U, + 2248145024U, 2256527744U, 2264922752U, 2273312128U, 2281701248U, + 2290086272U, 2298476672U, 2306867072U, 2315251072U, 2323639168U, + 2332032128U, 2340420224U, 2348808064U, 2357196416U, 2365580416U, + 2373966976U, 2382363008U, 2390748544U, 2399139968U, 2407530368U, + 2415918976U, 2424307328U, 2432695424U, 2441084288U, 2449472384U, + 2457861248U, 2466247808U, 2474637184U, 2483026816U, 2491414144U, + 2499803776U, 2508191872U, 2516582272U, 2524970368U, 2533359232U, + 2541743488U, 2550134144U, 2558525056U, 2566913408U, 2575301504U, + 2583686528U, 2592073856U, 2600467328U, 2608856192U, 2617240448U, + 2625631616U, 2634022016U, 2642407552U, 2650796416U, 2659188352U, + 2667574912U, 2675965312U, 2684352896U, 2692738688U, 2701130624U, + 2709518464U, 2717907328U, 2726293376U, 2734685056U, 2743073152U, + 2751462016U, 2759851648U, 2768232832U, 2776625536U, 2785017728U, + 2793401984U, 2801794432U, 2810182016U, 2818571648U, 2826959488U, + 2835349376U, 2843734144U, 2852121472U, 2860514432U, 2868900992U, + 2877286784U, 2885676928U, 2894069632U, 2902451584U, 2910843008U, + 2919234688U, 2927622784U, 2936011648U, 2944400768U, 2952789376U, + 2961177728U, 2969565568U, 2977951616U, 2986338944U, 2994731392U, + 3003120256U, 3011508352U, 3019895936U, 3028287104U, 3036675968U, + 3045063808U, 3053452928U, 3061837696U, 3070228352U, 3078615424U, + 3087003776U, 3095394944U, 3103782272U, 3112173184U, 3120562048U, + 3128944768U, 3137339264U, 3145725056U, 3154109312U, 3162505088U, + 3170893184U, 3179280256U, 3187669376U, 3196056704U, 3204445568U, + 3212836736U, 3221224064U, 3229612928U, 3238002304U, 3246391168U, + 3254778496U, 3263165824U, 3271556224U, 3279944576U, 3288332416U, + 3296719232U, 3305110912U, 3313500032U, 3321887104U, 3330273152U, + 3338658944U, 3347053184U, 3355440512U, 3363827072U, 3372220288U, + 3380608384U, 3388997504U, 3397384576U, 3405774208U, 3414163072U, + 3422551936U, 3430937984U, 3439328384U, 3447714176U, 3456104576U, + 3464493952U, 3472883584U, 3481268864U, 3489655168U, 3498048896U, + 3506434432U, 3514826368U, 3523213952U, 3531603584U, 3539987072U, + 3548380288U, 3556763264U, 3565157248U, 3573545344U, 3581934464U, + 3590324096U, 3598712704U, 3607098752U, 3615488384U, 3623877248U, + 3632265856U, 3640646528U, 3649043584U, 3657430144U, 3665821568U, + 3674207872U, 3682597504U, 3690984832U, 3699367808U, 3707764352U, + 3716152448U, 3724541056U, 3732925568U, 3741318016U, 3749706368U, + 3758091136U, 3766481536U, 3774872704U, 3783260032U, 3791650432U, + 3800036224U, 3808427648U, 3816815488U, 3825204608U, 3833592704U, + 3841981568U, 3850370432U, 3858755968U, 3867147904U, 3875536256U, + 3883920512U, 3892313728U, 3900702592U, 3909087872U, 3917478784U, + 3925868416U, 3934256512U, 3942645376U, 3951032192U, 3959422336U, + 3967809152U, 3976200064U, 3984588416U, 3992974976U, 4001363584U, + 4009751168U, 4018141312U, 4026530432U, 4034911616U, 4043308928U, + 4051695488U, 4060084352U, 4068472448U, 4076862848U, 4085249408U, + 4093640576U, 4102028416U, 4110413696U, 4118805632U, 4127194496U, + 4135583104U, 4143971968U, 4152360832U, 4160746112U, 4169135744U, + 4177525888U, 4185912704U, 4194303616U, 4202691968U, 4211076736U, + 4219463552U, 4227855488U, 4236246656U, 4244633728U, 4253022848U, + 4261412224U, 4269799808U, 4278184832U, 4286578048U, 4294962304U, + 4303349632U, 4311743104U, 4320130432U, 4328521088U, 4336909184U, + 4345295488U, 4353687424U, 4362073472U, 4370458496U, 4378852736U, + 4387238528U, 4395630208U, 4404019072U, 4412407424U, 4420790656U, + 4429182848U, 4437571456U, 4445962112U, 4454344064U, 4462738048U, + 4471119232U, 4479516544U, 4487904128U, 4496289664U, 4504682368U, + 4513068416U, 4521459584U, 4529846144U, 4538232704U, 4546619776U, + 4555010176U, 4563402112U, 4571790208U, 4580174464U, 4588567936U, + 4596957056U, 4605344896U, 4613734016U, 4622119808U, 4630511488U, + 4638898816U, 4647287936U, 4655675264U, 4664065664U, 4672451968U, + 4680842624U, 4689231488U, 4697620352U, 4706007424U, 4714397056U, + 4722786176U, 4731173248U, 4739562368U, 4747951744U, 4756340608U, + 4764727936U, 4773114496U, 4781504384U, 4789894784U, 4798283648U, + 4806667648U, 4815059584U, 4823449472U, 4831835776U, 4840226176U, + 4848612224U, 4857003392U, 4865391488U, 4873780096U, 4882169728U, + 4890557312U, 4898946944U, 4907333248U, 4915722368U, 4924110976U, + 4932499328U, 4940889728U, 4949276032U, 4957666432U, 4966054784U, + 4974438016U, 4982831488U, 4991221376U, 4999607168U, 5007998848U, + 5016386432U, 5024763776U, 5033164672U, 5041544576U, 5049941888U, + 5058329728U, 5066717056U, 5075107456U, 5083494272U, 5091883904U, + 5100273536U, 5108662144U, 5117048192U, 5125436032U, 5133827456U, + 5142215296U, 5150605184U, 5158993024U, 5167382144U, 5175769472U, + 5184157568U, 5192543872U, 5200936064U, 5209324928U, 5217711232U, + 5226102656U, 5234490496U, 5242877312U, 5251263872U, 5259654016U, + 5268040832U, 5276434304U, 5284819328U, 5293209728U, 5301598592U, + 5309986688U, 5318374784U, 5326764416U, 5335151488U, 5343542144U, + 5351929472U, 5360319872U, 5368706944U, 5377096576U, 5385484928U, + 5393871232U, 5402263424U, 5410650496U, 5419040384U, 5427426944U, + 5435816576U, 5444205952U, 5452594816U, 5460981376U, 5469367936U, + 5477760896U, 5486148736U, 5494536832U, 5502925952U, 5511315328U, + 5519703424U, 5528089984U, 5536481152U, 5544869504U, 5553256064U, + 5561645696U, 5570032768U, 5578423936U, 5586811264U, 5595193216U, + 5603585408U, 5611972736U, 5620366208U, 5628750464U, 5637143936U, + 5645528192U, 5653921408U, 5662310272U, 5670694784U, 5679082624U, + 5687474048U, 5695864448U, 5704251008U, 5712641408U, 5721030272U, + 5729416832U, 5737806208U, 5746194304U, 5754583936U, 5762969984U, + 5771358592U, 5779748224U, 5788137856U, 5796527488U, 5804911232U, + 5813300608U, 5821692544U, 5830082176U, 5838468992U, 5846855552U, + 5855247488U, 5863636096U, 5872024448U, 5880411008U, 5888799872U, + 5897186432U, 5905576832U, 5913966976U, 5922352768U, 5930744704U, + 5939132288U, 5947522432U, 5955911296U, 5964299392U, 5972688256U, + 5981074304U, 5989465472U, 5997851008U, 6006241408U, 6014627968U, + 6023015552U, 6031408256U, 6039796096U, 6048185216U, 6056574848U, + 6064963456U, 6073351808U, 6081736064U, 6090128768U, 6098517632U, + 6106906496U, 6115289216U, 6123680896U, 6132070016U, 6140459648U, + 6148849024U, 6157237376U, 6165624704U, 6174009728U, 6182403712U, + 6190792064U, 6199176064U, 6207569792U, 6215952256U, 6224345216U, + 6232732544U, 6241124224U, 6249510272U, 6257899136U, 6266287744U, + 6274676864U, 6283065728U, 6291454336U, 6299843456U, 6308232064U, + 6316620928U, 6325006208U, 6333395584U, 6341784704U, 6350174848U, + 6358562176U, 6366951296U, 6375337856U, 6383729536U, 6392119168U, + 6400504192U, 6408895616U, 6417283456U, 6425673344U, 6434059136U, + 6442444672U, 6450837376U, 6459223424U, 6467613056U, 6476004224U, + 6484393088U, 6492781952U, 6501170048U, 6509555072U, 6517947008U, + 6526336384U, 6534725504U, 6543112832U, 6551500672U, 6559888768U, + 6568278656U, 6576662912U, 6585055616U, 6593443456U, 6601834112U, + 6610219648U, 6618610304U, 6626999168U, 6635385472U, 6643777408U, + 6652164224U, 6660552832U, 6668941952U, 6677330048U, 6685719424U, + 6694107776U, 6702493568U, 6710882176U, 6719274112U, 6727662976U, + 6736052096U, 6744437632U, 6752825984U, 6761213824U, 6769604224U, + 6777993856U, 6786383488U, 6794770816U, 6803158144U, 6811549312U, + 6819937664U, 6828326528U, 6836706176U, 6845101696U, 6853491328U, + 6861880448U, 6870269312U, 6878655104U, 6887046272U, 6895433344U, + 6903822208U, 6912212864U, 6920596864U, 6928988288U, 6937377152U, + 6945764992U, 6954149248U, 6962544256U, 6970928768U, 6979317376U, + 6987709312U, 6996093824U, 7004487296U, 7012875392U, 7021258624U, + 7029652352U, 7038038912U, 7046427776U, 7054818944U, 7063207808U, + 7071595136U, 7079980928U, 7088372608U, 7096759424U, 7105149824U, + 7113536896U, 7121928064U, 7130315392U, 7138699648U, 7147092352U, + 7155479168U, 7163865728U, 7172249984U, 7180648064U, 7189036672U, + 7197424768U, 7205810816U, 7214196608U, 7222589824U, 7230975104U, + 7239367552U, 7247755904U, 7256145536U, 7264533376U, 7272921472U, + 7281308032U, 7289694848U, 7298088832U, 7306471808U, 7314864512U, + 7323253888U, 7331643008U, 7340029568U, 7348419712U, 7356808832U, + 7365196672U, 7373585792U, 7381973888U, 7390362752U, 7398750592U, + 7407138944U, 7415528576U, 7423915648U, 7432302208U, 7440690304U, + 7449080192U, 7457472128U, 7465860992U, 7474249088U, 7482635648U, + 7491023744U, 7499412608U, 7507803008U, 7516192384U, 7524579968U, + 7532967296U, 7541358464U, 7549745792U, 7558134656U, 7566524032U, + 7574912896U, 7583300992U, 7591690112U, 7600075136U, 7608466816U, + 7616854912U, 7625244544U, 7633629824U, 7642020992U, 7650410368U, + 7658794112U, 7667187328U, 7675574912U, 7683961984U, 7692349568U, + 7700739712U, 7709130368U, 7717519232U, 7725905536U, 7734295424U, + 7742683264U, 7751069056U, 7759457408U, 7767849088U, 7776238208U, + 7784626816U, 7793014912U, 7801405312U, 7809792128U, 7818179968U, + 7826571136U, 7834957184U, 7843347328U, 7851732352U, 7860124544U, + 7868512384U, 7876902016U, 7885287808U, 7893679744U, 7902067072U, + 7910455936U, 7918844288U, 7927230848U, 7935622784U, 7944009344U, + 7952400256U, 7960786048U, 7969176704U, 7977565312U, 7985953408U, + 7994339968U, 8002730368U, 8011119488U, 8019508096U, 8027896192U, + 8036285056U, 8044674688U, 8053062272U, 8061448832U, 8069838464U, + 8078227328U, 8086616704U, 8095006592U, 8103393664U, 8111783552U, + 8120171392U, 8128560256U, 8136949376U, 8145336704U, 8153726848U, + 8162114944U, 8170503296U, 8178891904U, 8187280768U, 8195669632U, + 8204058496U, 8212444544U, 8220834176U, 8229222272U, 8237612672U, + 8246000768U, 8254389376U, 8262775168U, 8271167104U, 8279553664U, + 8287944064U, 8296333184U, 8304715136U, 8313108352U, 8321497984U, + 8329885568U, 8338274432U, 8346663296U, 8355052928U, 8363441536U, + 8371828352U, 8380217984U, 8388606592U, 8396996224U, 8405384576U, + 8413772672U, 8422161536U, 8430549376U, 8438939008U, 8447326592U, + 8455715456U, 8464104832U, 8472492928U, 8480882048U, 8489270656U, + 8497659776U, 8506045312U, 8514434944U, 8522823808U, 8531208832U, + 8539602304U, 8547990656U, 8556378752U, 8564768384U, 8573154176U, + 8581542784U, 8589933952U, 8598322816U, 8606705024U, 8615099264U, + 8623487872U, 8631876992U, 8640264064U, 8648653952U, 8657040256U, + 8665430656U, 8673820544U, 8682209152U, 8690592128U, 8698977152U, + 8707374464U, 8715763328U, 8724151424U, 8732540032U, 8740928384U, + 8749315712U, 8757704576U, 8766089344U, 8774480768U, 8782871936U, + 8791260032U, 8799645824U, 8808034432U, 8816426368U, 8824812928U, + 8833199488U, 8841591424U, 8849976448U, 8858366336U, 8866757248U, + 8875147136U, 8883532928U, 8891923328U, 8900306816U, 8908700288U, + 8917088384U, 8925478784U, 8933867392U, 8942250368U, 8950644608U, + 8959032704U, 8967420544U, 8975809664U, 8984197504U, 8992584064U, + 9000976256U, 9009362048U, 9017752448U, 9026141312U, 9034530688U, + 9042917504U, 9051307904U, 9059694208U, 9068084864U, 9076471424U, + 9084861824U, 9093250688U, 9101638528U, 9110027648U, 9118416512U, + 9126803584U, 9135188096U, 9143581312U, 9151969664U, 9160356224U, + 9168747136U, 9177134464U, 9185525632U, 9193910144U, 9202302848U, + 9210690688U, 9219079552U, 9227465344U, 9235854464U, 9244244864U, + 9252633472U, 9261021824U, 9269411456U, 9277799296U, 9286188928U, + 9294574208U, 9302965888U, 9311351936U, 9319740032U, 9328131968U, + 9336516736U, 9344907392U, 9353296768U, 9361685888U, 9370074752U, + 9378463616U, 9386849408U, 9395239808U, 9403629184U, 9412016512U, + 9420405376U, 9428795008U, 9437181568U, 9445570688U, 9453960832U, + 9462346624U, 9470738048U, 9479121536U, 9487515008U, 9495903616U, + 9504289664U, 9512678528U, 9521067904U, 9529456256U, 9537843584U, + 9546233728U, 9554621312U, 9563011456U, 9571398784U, 9579788672U, + 9588178304U, 9596567168U, 9604954496U, 9613343104U, 9621732992U, + 9630121856U, 9638508416U, 9646898816U, 9655283584U, 9663675776U, + 9672061312U, 9680449664U, 9688840064U, 9697230464U, 9705617536U, + 9714003584U, 9722393984U, 9730772608U, 9739172224U, 9747561088U, + 9755945344U, 9764338816U, 9772726144U, 9781116544U, 9789503872U, + 9797892992U, 9806282624U, 9814670464U, 9823056512U, 9831439232U, + 9839833984U, 9848224384U, 9856613504U, 9865000576U, 9873391232U, + 9881772416U, 9890162816U, 9898556288U, 9906940544U, 9915333248U, + 9923721088U, 9932108672U, 9940496512U, 9948888448U, 9957276544U, + 9965666176U, 9974048384U, 9982441088U, 9990830464U, 9999219584U, + 10007602816U, 10015996544U, 10024385152U, 10032774016U, 10041163648U, + 10049548928U, 10057940096U, 10066329472U, 10074717824U, 10083105152U, + 10091495296U, 10099878784U, 10108272256U, 10116660608U, 10125049216U, + 10133437312U, 10141825664U, 10150213504U, 10158601088U, 10166991232U, + 10175378816U, 10183766144U, 10192157312U, 10200545408U, 10208935552U, + 10217322112U, 10225712768U, 10234099328U, 10242489472U, 10250876032U, + 10259264896U, 10267656064U, 10276042624U, 10284429184U, 10292820352U, + 10301209472U, 10309598848U, 10317987712U, 10326375296U, 10334763392U, + 10343153536U, 10351541632U, 10359930752U, 10368318592U, 10376707456U, + 10385096576U, 10393484672U, 10401867136U, 10410262144U, 10418647424U, + 10427039104U, 10435425664U, 10443810176U, 10452203648U, 10460589952U, + 10468982144U, 10477369472U, 10485759104U, 10494147712U, 10502533504U, + 10510923392U, 10519313536U, 10527702656U, 10536091264U, 10544478592U, + 10552867712U, 10561255808U, 10569642368U, 10578032768U, 10586423168U, + 10594805632U, 10603200128U, 10611588992U, 10619976064U, 10628361344U, + 10636754048U, 10645143424U, 10653531776U, 10661920384U, 10670307968U, + 10678696832U, 10687086464U, 10695475072U, 10703863168U, 10712246144U, + 10720639616U, 10729026688U, 10737414784U, 10745806208U, 10754190976U, + 10762581376U, 10770971264U, 10779356288U, 10787747456U, 10796135552U, + 10804525184U, 10812915584U, 10821301888U, 10829692288U, 10838078336U, + 10846469248U, 10854858368U, 10863247232U, 10871631488U, 10880023424U, + 10888412032U, 10896799616U, 10905188992U, 10913574016U, 10921964672U, + 10930352768U, 10938742912U, 10947132544U, 10955518592U, 10963909504U, + 10972298368U, 10980687488U, 10989074816U, 10997462912U, 11005851776U, + 11014241152U, 11022627712U, 11031017344U, 11039403904U, 11047793024U, + 11056184704U, 11064570752U, 11072960896U, 11081343872U, 11089737856U, + 11098128256U, 11106514816U, 11114904448U, 11123293568U, 11131680128U, + 11140065152U, 11148458368U, 11156845696U, 11165236864U, 11173624192U, + 11182013824U, 11190402688U, 11198790784U, 11207179136U, 11215568768U, + 11223957376U, 11232345728U, 11240734592U, 11249122688U, 11257511296U, + 11265899648U, 11274285952U, 11282675584U, 11291065472U, 11299452544U, + 11307842432U, 11316231296U, 11324616832U, 11333009024U, 11341395584U, + 11349782656U, 11358172288U, 11366560384U, 11374950016U, 11383339648U, + 11391721856U, 11400117376U, 11408504192U, 11416893568U, 11425283456U, + 11433671552U, 11442061184U, 11450444672U, 11458837888U, 11467226752U, + 11475611776U, 11484003968U, 11492392064U, 11500780672U, 11509169024U, + 11517550976U, 11525944448U, 11534335616U, 11542724224U, 11551111808U, + 11559500672U, 11567890304U, 11576277376U, 11584667008U, 11593056128U, + 11601443456U, 11609830016U, 11618221952U, 11626607488U, 11634995072U, + 11643387776U, 11651775104U, 11660161664U, 11668552576U, 11676940928U, + 11685330304U, 11693718656U, 11702106496U, 11710496128U, 11718882688U, + 11727273088U, 11735660416U, 11744050048U, 11752437376U, 11760824704U, + 11769216128U, 11777604736U, 11785991296U, 11794381952U, 11802770048U, + 11811157888U, 11819548544U, 11827932544U, 11836324736U, 11844713344U, + 11853100928U, 11861486464U, 11869879936U, 11878268032U, 11886656896U, + 11895044992U, 11903433088U, 11911822976U, 11920210816U, 11928600448U, + 11936987264U, 11945375872U, 11953761152U, 11962151296U, 11970543488U, + 11978928512U, 11987320448U, 11995708288U, 12004095104U, 12012486272U, + 12020875136U, 12029255552U, 12037652096U, 12046039168U, 12054429568U, + 12062813824U, 12071206528U, 12079594624U, 12087983744U, 12096371072U, + 12104759936U, 12113147264U, 12121534592U, 12129924992U, 12138314624U, + 12146703232U, 12155091584U, 12163481216U, 12171864704U, 12180255872U, + 12188643968U, 12197034112U, 12205424512U, 12213811328U, 12222199424U, + 12230590336U, 12238977664U, 12247365248U, 12255755392U, 12264143488U, + 12272531584U, 12280920448U, 12289309568U, 12297694592U, 12306086528U, + 12314475392U, 12322865024U, 12331253632U, 12339640448U, 12348029312U, + 12356418944U, 12364805248U, 12373196672U, 12381580928U, 12389969024U, + 12398357632U, 12406750592U, 12415138432U, 12423527552U, 12431916416U, + 12440304512U, 12448692352U, 12457081216U, 12465467776U, 12473859968U, + 12482245504U, 12490636672U, 12499025536U, 12507411584U, 12515801728U, + 12524190592U, 12532577152U, 12540966272U, 12549354368U, 12557743232U, + 12566129536U, 12574523264U, 12582911872U, 12591299456U, 12599688064U, + 12608074624U, 12616463488U, 12624845696U, 12633239936U, 12641631616U, + 12650019968U, 12658407296U, 12666795136U, 12675183232U, 12683574656U, + 12691960192U, 12700350592U, 12708740224U, 12717128576U, 12725515904U, + 12733906816U, 12742295168U, 12750680192U, 12759071872U, 12767460736U, + 12775848832U, 12784236928U, 12792626816U, 12801014656U, 12809404288U, + 12817789312U, 12826181504U, 12834568832U, 12842954624U, 12851345792U, + 12859732352U, 12868122496U, 12876512128U, 12884901248U, 12893289088U, + 12901672832U, 12910067584U, 12918455168U, 12926842496U, 12935232896U, + 12943620736U, 12952009856U, 12960396928U, 12968786816U, 12977176192U, + 12985563776U, 12993951104U, 13002341504U, 13010730368U, 13019115392U, + 13027506304U, 13035895168U, 13044272512U, 13052673152U, 13061062528U, + 13069446272U, 13077838976U, 13086227072U, 13094613632U, 13103000192U, + 13111393664U, 13119782528U, 13128157568U, 13136559232U, 13144945024U, + 13153329536U, 13161724288U, 13170111872U, 13178502784U, 13186884736U, + 13195279744U, 13203667072U, 13212057472U, 13220445824U, 13228832128U, + 13237221248U, 13245610624U, 13254000512U, 13262388352U, 13270777472U, + 13279166336U, 13287553408U, 13295943296U, 13304331904U, 13312719488U, + 13321108096U, 13329494656U, 13337885824U, 13346274944U, 13354663808U, + 13363051136U, 13371439232U, 13379825024U, 13388210816U, 13396605056U, + 13404995456U, 13413380224U, 13421771392U, 13430159744U, 13438546048U, + 13446937216U, 13455326848U, 13463708288U, 13472103808U, 13480492672U, + 13488875648U, 13497269888U, 13505657728U, 13514045312U, 13522435712U, + 13530824576U, 13539210112U, 13547599232U, 13555989376U, 13564379008U, + 13572766336U, 13581154432U, 13589544832U, 13597932928U, 13606320512U, + 13614710656U, 13623097472U, 13631477632U, 13639874944U, 13648264064U, + 13656652928U, 13665041792U, 13673430656U, 13681818496U, 13690207616U, + 13698595712U, 13706982272U, 13715373184U, 13723762048U, 13732150144U, + 13740536704U, 13748926592U, 13757316224U, 13765700992U, 13774090112U, + 13782477952U, 13790869376U, 13799259008U, 13807647872U, 13816036736U, + 13824425344U, 13832814208U, 13841202304U, 13849591424U, 13857978752U, + 13866368896U, 13874754688U, 13883145344U, 13891533184U, 13899919232U, + 13908311168U, 13916692096U, 13925085056U, 13933473152U, 13941866368U, + 13950253696U, 13958643584U, 13967032192U, 13975417216U, 13983807616U, + 13992197504U, 14000582272U, 14008973696U, 14017363072U, 14025752192U, + 14034137984U, 14042528384U, 14050918016U, 14059301504U, 14067691648U, + 14076083584U, 14084470144U, 14092852352U, 14101249664U, 14109635968U, + 14118024832U, 14126407552U, 14134804352U, 14143188608U, 14151577984U, + 14159968384U, 14168357248U, 14176741504U, 14185127296U, 14193521024U, + 14201911424U, 14210301824U, 14218685056U, 14227067264U, 14235467392U, + 14243855488U, 14252243072U, 14260630144U, 14269021568U, 14277409408U, + 14285799296U, 14294187904U, 14302571392U, 14310961792U, 14319353728U, + 14327738752U, 14336130944U, 14344518784U, 14352906368U, 14361296512U, + 14369685376U, 14378071424U, 14386462592U, 14394848128U, 14403230848U, + 14411627392U, 14420013952U, 14428402304U, 14436793472U, 14445181568U, + 14453569664U, 14461959808U, 14470347904U, 14478737024U, 14487122816U, + 14495511424U, 14503901824U, 14512291712U, 14520677504U, 14529064832U, + 14537456768U, 14545845632U, 14554234496U, 14562618496U, 14571011456U, + 14579398784U, 14587789184U, 14596172672U, 14604564608U, 14612953984U, + 14621341312U, 14629724288U, 14638120832U, 14646503296U, 14654897536U, + 14663284864U, 14671675264U, 14680061056U, 14688447616U, 14696835968U, + 14705228416U, 14713616768U, 14722003328U, 14730392192U, 14738784128U, + 14747172736U, 14755561088U, 14763947648U, 14772336512U, 14780725376U, + 14789110144U, 14797499776U, 14805892736U, 14814276992U, 14822670208U, + 14831056256U, 14839444352U, 14847836032U, 14856222848U, 14864612992U, + 14872997504U, 14881388672U, 14889775744U, 14898165376U, 14906553472U, + 14914944896U, 14923329664U, 14931721856U, 14940109696U, 14948497024U, + 14956887424U, 14965276544U, 14973663616U, 14982053248U, 14990439808U, + 14998830976U, 15007216768U, 15015605888U, 15023995264U, 15032385152U, + 15040768384U, 15049154944U, 15057549184U, 15065939072U, 15074328448U, + 15082715008U, 15091104128U, 15099493504U, 15107879296U, 15116269184U, + 15124659584U, 15133042304U, 15141431936U, 15149824384U, 15158214272U, + 15166602368U, 15174991232U, 15183378304U, 15191760512U, 15200154496U, + 15208542592U, 15216931712U, 15225323392U, 15233708416U, 15242098048U, + 15250489216U, 15258875264U, 15267265408U, 15275654528U, 15284043136U, + 15292431488U, 15300819584U, 15309208192U, 15317596544U, 15325986176U, + 15334374784U, 15342763648U, 15351151744U, 15359540608U, 15367929728U, + 15376318336U, 15384706432U, 15393092992U, 15401481856U, 15409869952U, + 15418258816U, 15426649984U, 15435037568U, 15443425664U, 15451815296U, + 15460203392U, 15468589184U, 15476979328U, 15485369216U, 15493755776U, + 15502146944U, 15510534272U, 15518924416U, 15527311232U, 15535699072U, + 15544089472U, 15552478336U, 15560866688U, 15569254528U, 15577642624U, + 15586031488U, 15594419072U, 15602809472U, 15611199104U, 15619586432U, + 15627975296U, 15636364928U, 15644753792U, 15653141888U, 15661529216U, + 15669918848U, 15678305152U, 15686696576U, 15695083136U, 15703474048U, + 15711861632U, 15720251264U, 15728636288U, 15737027456U, 15745417088U, + 15753804928U, 15762194048U, 15770582656U, 15778971008U, 15787358336U, + 15795747712U, 15804132224U, 15812523392U, 15820909696U, 15829300096U, + 15837691264U, 15846071936U, 15854466944U, 15862855808U, 15871244672U, + 15879634816U, 15888020608U, 15896409728U, 15904799104U, 15913185152U, + 15921577088U, 15929966464U, 15938354816U, 15946743424U, 15955129472U, + 15963519872U, 15971907968U, 15980296064U, 15988684928U, 15997073024U, + 16005460864U, 16013851264U, 16022241152U, 16030629248U, 16039012736U, + 16047406976U, 16055794816U, 16064181376U, 16072571264U, 16080957824U, + 16089346688U, 16097737856U, 16106125184U, 16114514816U, 16122904192U, + 16131292544U, 16139678848U, 16148066944U, 16156453504U, 16164839552U, + 16173236096U, 16181623424U, 16190012032U, 16198401152U, 16206790528U, + 16215177344U, 16223567744U, 16231956352U, 16240344704U, 16248731008U, + 16257117824U, 16265504384U, 16273898624U, 16282281856U, 16290668672U, + 16299064192U, 16307449216U, 16315842176U, 16324230016U, 16332613504U, + 16341006464U, 16349394304U, 16357783168U, 16366172288U, 16374561664U, + 16382951296U, 16391337856U, 16399726208U, 16408116352U, 16416505472U, + 16424892032U, 16433282176U, 16441668224U, 16450058624U, 16458448768U, + 16466836864U, 16475224448U, 16483613056U, 16492001408U, 16500391808U, + 16508779648U, 16517166976U, 16525555328U, 16533944192U, 16542330752U, + 16550719616U, 16559110528U, 16567497088U, 16575888512U, 16584274816U, + 16592665472U, 16601051008U, 16609442944U, 16617832064U, 16626218624U, + 16634607488U, 16642996096U, 16651385728U, 16659773824U, 16668163712U, + 16676552576U, 16684938112U, 16693328768U, 16701718144U, 16710095488U, + 16718492288U, 16726883968U, 16735272832U, 16743661184U, 16752049792U, + 16760436608U, 16768827008U, 16777214336U, 16785599104U, 16793992832U, + 16802381696U, 16810768768U, 16819151744U, 16827542656U, 16835934848U, + 16844323712U, 16852711552U, 16861101952U, 16869489536U, 16877876864U, + 16886265728U, 16894653056U, 16903044736U, 16911431296U, 16919821696U, + 16928207488U, 16936592768U, 16944987776U, 16953375616U, 16961763968U, + 16970152832U, 16978540928U, 16986929536U, 16995319168U, 17003704448U, + 17012096896U, 17020481152U, 17028870784U, 17037262208U, 17045649536U, + 17054039936U, 17062426496U, 17070814336U, 17079205504U, 17087592064U, + 17095978112U, 17104369024U, 17112759424U, 17121147776U, 17129536384U, + 17137926016U, 17146314368U, 17154700928U, 17163089792U, 17171480192U, + 17179864192U, 17188256896U, 17196644992U, 17205033856U, 17213423488U, + 17221811072U, 17230198912U, 17238588032U, 17246976896U, 17255360384U, + 17263754624U, 17272143232U, 17280530048U, 17288918912U, 17297309312U, + 17305696384U, 17314085504U, 17322475136U, 17330863744U, 17339252096U, + 17347640192U, 17356026496U, 17364413824U, 17372796544U, 17381190016U, + 17389583488U, 17397972608U, 17406360704U, 17414748544U, 17423135872U, + 17431527296U, 17439915904U, 17448303232U, 17456691584U, 17465081728U, + 17473468288U, 17481857408U, 17490247552U, 17498635904U, 17507022464U, + 17515409024U, 17523801728U, 17532189824U, 17540577664U, 17548966016U, + 17557353344U, 17565741184U, 17574131584U, 17582519168U, 17590907008U, + 17599296128U, 17607687808U, 17616076672U, 17624455808U, 17632852352U, + 17641238656U, 17649630848U, 17658018944U, 17666403968U, 17674794112U, + 17683178368U, 17691573376U, 17699962496U, 17708350592U, 17716739968U, + 17725126528U, 17733517184U, 17741898112U, 17750293888U, 17758673024U, + 17767070336U, 17775458432U, 17783848832U, 17792236928U, 17800625536U, + 17809012352U, 17817402752U, 17825785984U, 17834178944U, 17842563968U, + 17850955648U, 17859344512U, 17867732864U, 17876119424U, 17884511872U, + 17892900224U, 17901287296U, 17909677696U, 17918058112U, 17926451072U, + 17934843776U, 17943230848U, 17951609216U, 17960008576U, 17968397696U, + 17976784256U, 17985175424U, 17993564032U, 18001952128U, 18010339712U, + 18018728576U, 18027116672U, 18035503232U, 18043894144U, 18052283264U, + 18060672128U, 18069056384U, 18077449856U, 18085837184U, 18094225792U, + 18102613376U, 18111004544U, 18119388544U, 18127781248U, 18136170368U, + 18144558976U, 18152947328U, 18161336192U, 18169724288U, 18178108544U, + 18186498944U, 18194886784U, 18203275648U, 18211666048U, 18220048768U, + 18228444544U, 18236833408U, 18245220736U +}; + + +// Generated with the following Mathematica Code: + +// GetCacheSizes[n_] := Module[{ +// DataSetSizeBytesInit = 2^30, +// MixBytes = 128, +// DataSetGrowth = 2^23, +// HashBytes = 64, +// CacheMultiplier = 1024, +// j = 0}, +// Reap[ +// While[j < n, +// Module[{i = Floor[(DataSetSizeBytesInit + DataSetGrowth * j) / (CacheMultiplier * HashBytes)]}, +// While[! PrimeQ[i], i--]; +// Sow[i*HashBytes]; j++]]]][[2]][[1]] + +const uint64_t cache_sizes[2048] = { + 16776896U, 16907456U, 17039296U, 17170112U, 17301056U, 17432512U, 17563072U, + 17693888U, 17824192U, 17955904U, 18087488U, 18218176U, 18349504U, 18481088U, + 18611392U, 18742336U, 18874304U, 19004224U, 19135936U, 19267264U, 19398208U, + 19529408U, 19660096U, 19791424U, 19922752U, 20053952U, 20184896U, 20315968U, + 20446912U, 20576576U, 20709184U, 20840384U, 20971072U, 21102272U, 21233216U, + 21364544U, 21494848U, 21626816U, 21757376U, 21887552U, 22019392U, 22151104U, + 22281536U, 22412224U, 22543936U, 22675264U, 22806464U, 22935872U, 23068096U, + 23198272U, 23330752U, 23459008U, 23592512U, 23723968U, 23854912U, 23986112U, + 24116672U, 24247616U, 24378688U, 24509504U, 24640832U, 24772544U, 24903488U, + 25034432U, 25165376U, 25296704U, 25427392U, 25558592U, 25690048U, 25820096U, + 25951936U, 26081728U, 26214208U, 26345024U, 26476096U, 26606656U, 26737472U, + 26869184U, 26998208U, 27131584U, 27262528U, 27393728U, 27523904U, 27655744U, + 27786688U, 27917888U, 28049344U, 28179904U, 28311488U, 28441792U, 28573504U, + 28700864U, 28835648U, 28966208U, 29096768U, 29228608U, 29359808U, 29490752U, + 29621824U, 29752256U, 29882816U, 30014912U, 30144448U, 30273728U, 30406976U, + 30538432U, 30670784U, 30799936U, 30932672U, 31063744U, 31195072U, 31325248U, + 31456192U, 31588288U, 31719232U, 31850432U, 31981504U, 32110784U, 32243392U, + 32372672U, 32505664U, 32636608U, 32767808U, 32897344U, 33029824U, 33160768U, + 33289664U, 33423296U, 33554368U, 33683648U, 33816512U, 33947456U, 34076992U, + 34208704U, 34340032U, 34471744U, 34600256U, 34734016U, 34864576U, 34993984U, + 35127104U, 35258176U, 35386688U, 35518528U, 35650624U, 35782336U, 35910976U, + 36044608U, 36175808U, 36305728U, 36436672U, 36568384U, 36699968U, 36830656U, + 36961984U, 37093312U, 37223488U, 37355072U, 37486528U, 37617472U, 37747904U, + 37879232U, 38009792U, 38141888U, 38272448U, 38403392U, 38535104U, 38660672U, + 38795584U, 38925632U, 39059264U, 39190336U, 39320768U, 39452096U, 39581632U, + 39713984U, 39844928U, 39974848U, 40107968U, 40238144U, 40367168U, 40500032U, + 40631744U, 40762816U, 40894144U, 41023552U, 41155904U, 41286208U, 41418304U, + 41547712U, 41680448U, 41811904U, 41942848U, 42073792U, 42204992U, 42334912U, + 42467008U, 42597824U, 42729152U, 42860096U, 42991552U, 43122368U, 43253696U, + 43382848U, 43515712U, 43646912U, 43777088U, 43907648U, 44039104U, 44170432U, + 44302144U, 44433344U, 44564288U, 44694976U, 44825152U, 44956864U, 45088448U, + 45219008U, 45350464U, 45481024U, 45612608U, 45744064U, 45874496U, 46006208U, + 46136768U, 46267712U, 46399424U, 46529344U, 46660672U, 46791488U, 46923328U, + 47053504U, 47185856U, 47316928U, 47447872U, 47579072U, 47710144U, 47839936U, + 47971648U, 48103232U, 48234176U, 48365248U, 48496192U, 48627136U, 48757312U, + 48889664U, 49020736U, 49149248U, 49283008U, 49413824U, 49545152U, 49675712U, + 49807168U, 49938368U, 50069056U, 50200256U, 50331584U, 50462656U, 50593472U, + 50724032U, 50853952U, 50986048U, 51117632U, 51248576U, 51379904U, 51510848U, + 51641792U, 51773248U, 51903296U, 52035136U, 52164032U, 52297664U, 52427968U, + 52557376U, 52690112U, 52821952U, 52952896U, 53081536U, 53213504U, 53344576U, + 53475776U, 53608384U, 53738816U, 53870528U, 54000832U, 54131776U, 54263744U, + 54394688U, 54525248U, 54655936U, 54787904U, 54918592U, 55049152U, 55181248U, + 55312064U, 55442752U, 55574336U, 55705024U, 55836224U, 55967168U, 56097856U, + 56228672U, 56358592U, 56490176U, 56621888U, 56753728U, 56884928U, 57015488U, + 57146816U, 57278272U, 57409216U, 57540416U, 57671104U, 57802432U, 57933632U, + 58064576U, 58195264U, 58326976U, 58457408U, 58588864U, 58720192U, 58849984U, + 58981696U, 59113024U, 59243456U, 59375552U, 59506624U, 59637568U, 59768512U, + 59897792U, 60030016U, 60161984U, 60293056U, 60423872U, 60554432U, 60683968U, + 60817216U, 60948032U, 61079488U, 61209664U, 61341376U, 61471936U, 61602752U, + 61733696U, 61865792U, 61996736U, 62127808U, 62259136U, 62389568U, 62520512U, + 62651584U, 62781632U, 62910784U, 63045056U, 63176128U, 63307072U, 63438656U, + 63569216U, 63700928U, 63831616U, 63960896U, 64093888U, 64225088U, 64355392U, + 64486976U, 64617664U, 64748608U, 64879424U, 65009216U, 65142464U, 65273792U, + 65402816U, 65535424U, 65666752U, 65797696U, 65927744U, 66060224U, 66191296U, + 66321344U, 66453056U, 66584384U, 66715328U, 66846656U, 66977728U, 67108672U, + 67239104U, 67370432U, 67501888U, 67631296U, 67763776U, 67895104U, 68026304U, + 68157248U, 68287936U, 68419264U, 68548288U, 68681408U, 68811968U, 68942912U, + 69074624U, 69205568U, 69337024U, 69467584U, 69599168U, 69729472U, 69861184U, + 69989824U, 70122944U, 70253888U, 70385344U, 70515904U, 70647232U, 70778816U, + 70907968U, 71040832U, 71171648U, 71303104U, 71432512U, 71564992U, 71695168U, + 71826368U, 71958464U, 72089536U, 72219712U, 72350144U, 72482624U, 72613568U, + 72744512U, 72875584U, 73006144U, 73138112U, 73268672U, 73400128U, 73530944U, + 73662272U, 73793344U, 73924544U, 74055104U, 74185792U, 74316992U, 74448832U, + 74579392U, 74710976U, 74841664U, 74972864U, 75102784U, 75233344U, 75364544U, + 75497024U, 75627584U, 75759296U, 75890624U, 76021696U, 76152256U, 76283072U, + 76414144U, 76545856U, 76676672U, 76806976U, 76937792U, 77070016U, 77200832U, + 77331392U, 77462464U, 77593664U, 77725376U, 77856448U, 77987776U, 78118336U, + 78249664U, 78380992U, 78511424U, 78642496U, 78773056U, 78905152U, 79033664U, + 79166656U, 79297472U, 79429568U, 79560512U, 79690816U, 79822784U, 79953472U, + 80084672U, 80214208U, 80346944U, 80477632U, 80608576U, 80740288U, 80870848U, + 81002048U, 81133504U, 81264448U, 81395648U, 81525952U, 81657536U, 81786304U, + 81919808U, 82050112U, 82181312U, 82311616U, 82443968U, 82573376U, 82705984U, + 82835776U, 82967744U, 83096768U, 83230528U, 83359552U, 83491264U, 83622464U, + 83753536U, 83886016U, 84015296U, 84147776U, 84277184U, 84409792U, 84540608U, + 84672064U, 84803008U, 84934336U, 85065152U, 85193792U, 85326784U, 85458496U, + 85589312U, 85721024U, 85851968U, 85982656U, 86112448U, 86244416U, 86370112U, + 86506688U, 86637632U, 86769344U, 86900672U, 87031744U, 87162304U, 87293632U, + 87424576U, 87555392U, 87687104U, 87816896U, 87947968U, 88079168U, 88211264U, + 88341824U, 88473152U, 88603712U, 88735424U, 88862912U, 88996672U, 89128384U, + 89259712U, 89390272U, 89521984U, 89652544U, 89783872U, 89914816U, 90045376U, + 90177088U, 90307904U, 90438848U, 90569152U, 90700096U, 90832832U, 90963776U, + 91093696U, 91223744U, 91356992U, 91486784U, 91618496U, 91749824U, 91880384U, + 92012224U, 92143552U, 92273344U, 92405696U, 92536768U, 92666432U, 92798912U, + 92926016U, 93060544U, 93192128U, 93322816U, 93453632U, 93583936U, 93715136U, + 93845056U, 93977792U, 94109504U, 94240448U, 94371776U, 94501184U, 94632896U, + 94764224U, 94895552U, 95023424U, 95158208U, 95287744U, 95420224U, 95550016U, + 95681216U, 95811904U, 95943872U, 96075328U, 96203584U, 96337856U, 96468544U, + 96599744U, 96731072U, 96860992U, 96992576U, 97124288U, 97254848U, 97385536U, + 97517248U, 97647808U, 97779392U, 97910464U, 98041408U, 98172608U, 98303168U, + 98434496U, 98565568U, 98696768U, 98827328U, 98958784U, 99089728U, 99220928U, + 99352384U, 99482816U, 99614272U, 99745472U, 99876416U, 100007104U, + 100138048U, 100267072U, 100401088U, 100529984U, 100662592U, 100791872U, + 100925248U, 101056064U, 101187392U, 101317952U, 101449408U, 101580608U, + 101711296U, 101841728U, 101973824U, 102104896U, 102235712U, 102366016U, + 102498112U, 102628672U, 102760384U, 102890432U, 103021888U, 103153472U, + 103284032U, 103415744U, 103545152U, 103677248U, 103808576U, 103939648U, + 104070976U, 104201792U, 104332736U, 104462528U, 104594752U, 104725952U, + 104854592U, 104988608U, 105118912U, 105247808U, 105381184U, 105511232U, + 105643072U, 105774784U, 105903296U, 106037056U, 106167872U, 106298944U, + 106429504U, 106561472U, 106691392U, 106822592U, 106954304U, 107085376U, + 107216576U, 107346368U, 107478464U, 107609792U, 107739712U, 107872192U, + 108003136U, 108131392U, 108265408U, 108396224U, 108527168U, 108657344U, + 108789568U, 108920384U, 109049792U, 109182272U, 109312576U, 109444928U, + 109572928U, 109706944U, 109837888U, 109969088U, 110099648U, 110230976U, + 110362432U, 110492992U, 110624704U, 110755264U, 110886208U, 111017408U, + 111148864U, 111279296U, 111410752U, 111541952U, 111673024U, 111803456U, + 111933632U, 112066496U, 112196416U, 112328512U, 112457792U, 112590784U, + 112715968U, 112852672U, 112983616U, 113114944U, 113244224U, 113376448U, + 113505472U, 113639104U, 113770304U, 113901376U, 114031552U, 114163264U, + 114294592U, 114425536U, 114556864U, 114687424U, 114818624U, 114948544U, + 115080512U, 115212224U, 115343296U, 115473472U, 115605184U, 115736128U, + 115867072U, 115997248U, 116128576U, 116260288U, 116391488U, 116522944U, + 116652992U, 116784704U, 116915648U, 117046208U, 117178304U, 117308608U, + 117440192U, 117569728U, 117701824U, 117833024U, 117964096U, 118094656U, + 118225984U, 118357312U, 118489024U, 118617536U, 118749632U, 118882112U, + 119012416U, 119144384U, 119275328U, 119406016U, 119537344U, 119668672U, + 119798464U, 119928896U, 120061376U, 120192832U, 120321728U, 120454336U, + 120584512U, 120716608U, 120848192U, 120979136U, 121109056U, 121241408U, + 121372352U, 121502912U, 121634752U, 121764416U, 121895744U, 122027072U, + 122157632U, 122289088U, 122421184U, 122550592U, 122682944U, 122813888U, + 122945344U, 123075776U, 123207488U, 123338048U, 123468736U, 123600704U, + 123731264U, 123861952U, 123993664U, 124124608U, 124256192U, 124386368U, + 124518208U, 124649024U, 124778048U, 124911296U, 125041088U, 125173696U, + 125303744U, 125432896U, 125566912U, 125696576U, 125829056U, 125958592U, + 126090304U, 126221248U, 126352832U, 126483776U, 126615232U, 126746432U, + 126876608U, 127008704U, 127139392U, 127270336U, 127401152U, 127532224U, + 127663552U, 127794752U, 127925696U, 128055232U, 128188096U, 128319424U, + 128449856U, 128581312U, 128712256U, 128843584U, 128973632U, 129103808U, + 129236288U, 129365696U, 129498944U, 129629888U, 129760832U, 129892288U, + 130023104U, 130154048U, 130283968U, 130416448U, 130547008U, 130678336U, + 130807616U, 130939456U, 131071552U, 131202112U, 131331776U, 131464384U, + 131594048U, 131727296U, 131858368U, 131987392U, 132120256U, 132250816U, + 132382528U, 132513728U, 132644672U, 132774976U, 132905792U, 133038016U, + 133168832U, 133299392U, 133429312U, 133562048U, 133692992U, 133823296U, + 133954624U, 134086336U, 134217152U, 134348608U, 134479808U, 134607296U, + 134741056U, 134872384U, 135002944U, 135134144U, 135265472U, 135396544U, + 135527872U, 135659072U, 135787712U, 135921472U, 136052416U, 136182848U, + 136313792U, 136444864U, 136576448U, 136707904U, 136837952U, 136970048U, + 137099584U, 137232064U, 137363392U, 137494208U, 137625536U, 137755712U, + 137887424U, 138018368U, 138149824U, 138280256U, 138411584U, 138539584U, + 138672832U, 138804928U, 138936128U, 139066688U, 139196864U, 139328704U, + 139460032U, 139590208U, 139721024U, 139852864U, 139984576U, 140115776U, + 140245696U, 140376512U, 140508352U, 140640064U, 140769856U, 140902336U, + 141032768U, 141162688U, 141294016U, 141426496U, 141556544U, 141687488U, + 141819584U, 141949888U, 142080448U, 142212544U, 142342336U, 142474432U, + 142606144U, 142736192U, 142868288U, 142997824U, 143129408U, 143258944U, + 143392448U, 143523136U, 143653696U, 143785024U, 143916992U, 144045632U, + 144177856U, 144309184U, 144440768U, 144570688U, 144701888U, 144832448U, + 144965056U, 145096384U, 145227584U, 145358656U, 145489856U, 145620928U, + 145751488U, 145883072U, 146011456U, 146144704U, 146275264U, 146407232U, + 146538176U, 146668736U, 146800448U, 146931392U, 147062336U, 147193664U, + 147324224U, 147455936U, 147586624U, 147717056U, 147848768U, 147979456U, + 148110784U, 148242368U, 148373312U, 148503232U, 148635584U, 148766144U, + 148897088U, 149028416U, 149159488U, 149290688U, 149420224U, 149551552U, + 149683136U, 149814976U, 149943616U, 150076352U, 150208064U, 150338624U, + 150470464U, 150600256U, 150732224U, 150862784U, 150993088U, 151125952U, + 151254976U, 151388096U, 151519168U, 151649728U, 151778752U, 151911104U, + 152042944U, 152174144U, 152304704U, 152435648U, 152567488U, 152698816U, + 152828992U, 152960576U, 153091648U, 153222976U, 153353792U, 153484096U, + 153616192U, 153747008U, 153878336U, 154008256U, 154139968U, 154270912U, + 154402624U, 154533824U, 154663616U, 154795712U, 154926272U, 155057984U, + 155188928U, 155319872U, 155450816U, 155580608U, 155712064U, 155843392U, + 155971136U, 156106688U, 156237376U, 156367424U, 156499264U, 156630976U, + 156761536U, 156892352U, 157024064U, 157155008U, 157284416U, 157415872U, + 157545536U, 157677248U, 157810496U, 157938112U, 158071744U, 158203328U, + 158334656U, 158464832U, 158596288U, 158727616U, 158858048U, 158988992U, + 159121216U, 159252416U, 159381568U, 159513152U, 159645632U, 159776192U, + 159906496U, 160038464U, 160169536U, 160300352U, 160430656U, 160563008U, + 160693952U, 160822208U, 160956352U, 161086784U, 161217344U, 161349184U, + 161480512U, 161611456U, 161742272U, 161873216U, 162002752U, 162135872U, + 162266432U, 162397888U, 162529216U, 162660032U, 162790976U, 162922048U, + 163052096U, 163184576U, 163314752U, 163446592U, 163577408U, 163707968U, + 163839296U, 163969984U, 164100928U, 164233024U, 164364224U, 164494912U, + 164625856U, 164756672U, 164887616U, 165019072U, 165150016U, 165280064U, + 165412672U, 165543104U, 165674944U, 165805888U, 165936832U, 166067648U, + 166198336U, 166330048U, 166461248U, 166591552U, 166722496U, 166854208U, + 166985408U, 167116736U, 167246656U, 167378368U, 167508416U, 167641024U, + 167771584U, 167903168U, 168034112U, 168164032U, 168295744U, 168427456U, + 168557632U, 168688448U, 168819136U, 168951616U, 169082176U, 169213504U, + 169344832U, 169475648U, 169605952U, 169738048U, 169866304U, 169999552U, + 170131264U, 170262464U, 170393536U, 170524352U, 170655424U, 170782016U, + 170917696U, 171048896U, 171179072U, 171310784U, 171439936U, 171573184U, + 171702976U, 171835072U, 171966272U, 172097216U, 172228288U, 172359232U, + 172489664U, 172621376U, 172747712U, 172883264U, 173014208U, 173144512U, + 173275072U, 173407424U, 173539136U, 173669696U, 173800768U, 173931712U, + 174063424U, 174193472U, 174325696U, 174455744U, 174586816U, 174718912U, + 174849728U, 174977728U, 175109696U, 175242688U, 175374272U, 175504832U, + 175636288U, 175765696U, 175898432U, 176028992U, 176159936U, 176291264U, + 176422592U, 176552512U, 176684864U, 176815424U, 176946496U, 177076544U, + 177209152U, 177340096U, 177470528U, 177600704U, 177731648U, 177864256U, + 177994816U, 178126528U, 178257472U, 178387648U, 178518464U, 178650176U, + 178781888U, 178912064U, 179044288U, 179174848U, 179305024U, 179436736U, + 179568448U, 179698496U, 179830208U, 179960512U, 180092608U, 180223808U, + 180354752U, 180485696U, 180617152U, 180748096U, 180877504U, 181009984U, + 181139264U, 181272512U, 181402688U, 181532608U, 181663168U, 181795136U, + 181926592U, 182057536U, 182190016U, 182320192U, 182451904U, 182582336U, + 182713792U, 182843072U, 182976064U, 183107264U, 183237056U, 183368384U, + 183494848U, 183631424U, 183762752U, 183893824U, 184024768U, 184154816U, + 184286656U, 184417984U, 184548928U, 184680128U, 184810816U, 184941248U, + 185072704U, 185203904U, 185335616U, 185465408U, 185596352U, 185727296U, + 185859904U, 185989696U, 186121664U, 186252992U, 186383552U, 186514112U, + 186645952U, 186777152U, 186907328U, 187037504U, 187170112U, 187301824U, + 187429184U, 187562048U, 187693504U, 187825472U, 187957184U, 188087104U, + 188218304U, 188349376U, 188481344U, 188609728U, 188743616U, 188874304U, + 189005248U, 189136448U, 189265088U, 189396544U, 189528128U, 189660992U, + 189791936U, 189923264U, 190054208U, 190182848U, 190315072U, 190447424U, + 190577984U, 190709312U, 190840768U, 190971328U, 191102656U, 191233472U, + 191364032U, 191495872U, 191626816U, 191758016U, 191888192U, 192020288U, + 192148928U, 192282176U, 192413504U, 192542528U, 192674752U, 192805952U, + 192937792U, 193068608U, 193198912U, 193330496U, 193462208U, 193592384U, + 193723456U, 193854272U, 193985984U, 194116672U, 194247232U, 194379712U, + 194508352U, 194641856U, 194772544U, 194900672U, 195035072U, 195166016U, + 195296704U, 195428032U, 195558592U, 195690304U, 195818176U, 195952576U, + 196083392U, 196214336U, 196345792U, 196476736U, 196607552U, 196739008U, + 196869952U, 197000768U, 197130688U, 197262784U, 197394368U, 197523904U, + 197656384U, 197787584U, 197916608U, 198049472U, 198180544U, 198310208U, + 198442432U, 198573632U, 198705088U, 198834368U, 198967232U, 199097792U, + 199228352U, 199360192U, 199491392U, 199621696U, 199751744U, 199883968U, + 200014016U, 200146624U, 200276672U, 200408128U, 200540096U, 200671168U, + 200801984U, 200933312U, 201062464U, 201194944U, 201326144U, 201457472U, + 201588544U, 201719744U, 201850816U, 201981632U, 202111552U, 202244032U, + 202374464U, 202505152U, 202636352U, 202767808U, 202898368U, 203030336U, + 203159872U, 203292608U, 203423296U, 203553472U, 203685824U, 203816896U, + 203947712U, 204078272U, 204208192U, 204341056U, 204472256U, 204603328U, + 204733888U, 204864448U, 204996544U, 205125568U, 205258304U, 205388864U, + 205517632U, 205650112U, 205782208U, 205913536U, 206044736U, 206176192U, + 206307008U, 206434496U, 206569024U, 206700224U, 206831168U, 206961856U, + 207093056U, 207223616U, 207355328U, 207486784U, 207616832U, 207749056U, + 207879104U, 208010048U, 208141888U, 208273216U, 208404032U, 208534336U, + 208666048U, 208796864U, 208927424U, 209059264U, 209189824U, 209321792U, + 209451584U, 209582656U, 209715136U, 209845568U, 209976896U, 210106432U, + 210239296U, 210370112U, 210501568U, 210630976U, 210763712U, 210894272U, + 211024832U, 211156672U, 211287616U, 211418176U, 211549376U, 211679296U, + 211812032U, 211942592U, 212074432U, 212204864U, 212334016U, 212467648U, + 212597824U, 212727616U, 212860352U, 212991424U, 213120832U, 213253952U, + 213385024U, 213515584U, 213645632U, 213777728U, 213909184U, 214040128U, + 214170688U, 214302656U, 214433728U, 214564544U, 214695232U, 214826048U, + 214956992U, 215089088U, 215219776U, 215350592U, 215482304U, 215613248U, + 215743552U, 215874752U, 216005312U, 216137024U, 216267328U, 216399296U, + 216530752U, 216661696U, 216790592U, 216923968U, 217054528U, 217183168U, + 217316672U, 217448128U, 217579072U, 217709504U, 217838912U, 217972672U, + 218102848U, 218233024U, 218364736U, 218496832U, 218627776U, 218759104U, + 218888896U, 219021248U, 219151936U, 219281728U, 219413056U, 219545024U, + 219675968U, 219807296U, 219938624U, 220069312U, 220200128U, 220331456U, + 220461632U, 220592704U, 220725184U, 220855744U, 220987072U, 221117888U, + 221249216U, 221378368U, 221510336U, 221642048U, 221772736U, 221904832U, + 222031808U, 222166976U, 222297536U, 222428992U, 222559936U, 222690368U, + 222820672U, 222953152U, 223083968U, 223213376U, 223345984U, 223476928U, + 223608512U, 223738688U, 223869376U, 224001472U, 224132672U, 224262848U, + 224394944U, 224524864U, 224657344U, 224788288U, 224919488U, 225050432U, + 225181504U, 225312704U, 225443776U, 225574592U, 225704768U, 225834176U, + 225966784U, 226097216U, 226229824U, 226360384U, 226491712U, 226623424U, + 226754368U, 226885312U, 227015104U, 227147456U, 227278528U, 227409472U, + 227539904U, 227669696U, 227802944U, 227932352U, 228065216U, 228196288U, + 228326464U, 228457792U, 228588736U, 228720064U, 228850112U, 228981056U, + 229113152U, 229243328U, 229375936U, 229505344U, 229636928U, 229769152U, + 229894976U, 230030272U, 230162368U, 230292416U, 230424512U, 230553152U, + 230684864U, 230816704U, 230948416U, 231079616U, 231210944U, 231342016U, + 231472448U, 231603776U, 231733952U, 231866176U, 231996736U, 232127296U, + 232259392U, 232388672U, 232521664U, 232652608U, 232782272U, 232914496U, + 233043904U, 233175616U, 233306816U, 233438528U, 233569984U, 233699776U, + 233830592U, 233962688U, 234092224U, 234221888U, 234353984U, 234485312U, + 234618304U, 234749888U, 234880832U, 235011776U, 235142464U, 235274048U, + 235403456U, 235535936U, 235667392U, 235797568U, 235928768U, 236057152U, + 236190272U, 236322752U, 236453312U, 236583616U, 236715712U, 236846528U, + 236976448U, 237108544U, 237239104U, 237371072U, 237501632U, 237630784U, + 237764416U, 237895232U, 238026688U, 238157632U, 238286912U, 238419392U, + 238548032U, 238681024U, 238812608U, 238941632U, 239075008U, 239206336U, + 239335232U, 239466944U, 239599168U, 239730496U, 239861312U, 239992384U, + 240122816U, 240254656U, 240385856U, 240516928U, 240647872U, 240779072U, + 240909632U, 241040704U, 241171904U, 241302848U, 241433408U, 241565248U, + 241696192U, 241825984U, 241958848U, 242088256U, 242220224U, 242352064U, + 242481856U, 242611648U, 242744896U, 242876224U, 243005632U, 243138496U, + 243268672U, 243400384U, 243531712U, 243662656U, 243793856U, 243924544U, + 244054592U, 244187072U, 244316608U, 244448704U, 244580032U, 244710976U, + 244841536U, 244972864U, 245104448U, 245233984U, 245365312U, 245497792U, + 245628736U, 245759936U, 245889856U, 246021056U, 246152512U, 246284224U, + 246415168U, 246545344U, 246675904U, 246808384U, 246939584U, 247070144U, + 247199552U, 247331648U, 247463872U, 247593536U, 247726016U, 247857088U, + 247987648U, 248116928U, 248249536U, 248380736U, 248512064U, 248643008U, + 248773312U, 248901056U, 249036608U, 249167552U, 249298624U, 249429184U, + 249560512U, 249692096U, 249822784U, 249954112U, 250085312U, 250215488U, + 250345792U, 250478528U, 250608704U, 250739264U, 250870976U, 251002816U, + 251133632U, 251263552U, 251395136U, 251523904U, 251657792U, 251789248U, + 251919424U, 252051392U, 252182464U, 252313408U, 252444224U, 252575552U, + 252706624U, 252836032U, 252968512U, 253099712U, 253227584U, 253361728U, + 253493056U, 253623488U, 253754432U, 253885504U, 254017216U, 254148032U, + 254279488U, 254410432U, 254541376U, 254672576U, 254803264U, 254933824U, + 255065792U, 255196736U, 255326528U, 255458752U, 255589952U, 255721408U, + 255851072U, 255983296U, 256114624U, 256244416U, 256374208U, 256507712U, + 256636096U, 256768832U, 256900544U, 257031616U, 257162176U, 257294272U, + 257424448U, 257555776U, 257686976U, 257818432U, 257949632U, 258079552U, + 258211136U, 258342464U, 258473408U, 258603712U, 258734656U, 258867008U, + 258996544U, 259127744U, 259260224U, 259391296U, 259522112U, 259651904U, + 259784384U, 259915328U, 260045888U, 260175424U, 260308544U, 260438336U, + 260570944U, 260700992U, 260832448U, 260963776U, 261092672U, 261226304U, + 261356864U, 261487936U, 261619648U, 261750592U, 261879872U, 262011968U, + 262143424U, 262274752U, 262404416U, 262537024U, 262667968U, 262799296U, + 262928704U, 263061184U, 263191744U, 263322944U, 263454656U, 263585216U, + 263716672U, 263847872U, 263978944U, 264108608U, 264241088U, 264371648U, + 264501184U, 264632768U, 264764096U, 264895936U, 265024576U, 265158464U, + 265287488U, 265418432U, 265550528U, 265681216U, 265813312U, 265943488U, + 266075968U, 266206144U, 266337728U, 266468032U, 266600384U, 266731072U, + 266862272U, 266993344U, 267124288U, 267255616U, 267386432U, 267516992U, + 267648704U, 267777728U, 267910592U, 268040512U, 268172096U, 268302784U, + 268435264U, 268566208U, 268696256U, 268828096U, 268959296U, 269090368U, + 269221312U, 269352256U, 269482688U, 269614784U, 269745856U, 269876416U, + 270007616U, 270139328U, 270270272U, 270401216U, 270531904U, 270663616U, + 270791744U, 270924736U, 271056832U, 271186112U, 271317184U, 271449536U, + 271580992U, 271711936U, 271843136U, 271973056U, 272105408U, 272236352U, + 272367296U, 272498368U, 272629568U, 272759488U, 272891456U, 273022784U, + 273153856U, 273284672U, 273415616U, 273547072U, 273677632U, 273808448U, + 273937088U, 274071488U, 274200896U, 274332992U, 274463296U, 274595392U, + 274726208U, 274857536U, 274988992U, 275118656U, 275250496U, 275382208U, + 275513024U, 275643968U, 275775296U, 275906368U, 276037184U, 276167872U, + 276297664U, 276429376U, 276560576U, 276692672U, 276822976U, 276955072U, + 277085632U, 277216832U, 277347008U, 277478848U, 277609664U, 277740992U, + 277868608U, 278002624U, 278134336U, 278265536U, 278395328U, 278526784U, + 278657728U, 278789824U, 278921152U, 279052096U, 279182912U, 279313088U, + 279443776U, 279576256U, 279706048U, 279838528U, 279969728U, 280099648U, + 280230976U, 280361408U, 280493632U, 280622528U, 280755392U, 280887104U, + 281018176U, 281147968U, 281278912U, 281411392U, 281542592U, 281673152U, + 281803712U, 281935552U, 282066496U, 282197312U, 282329024U, 282458816U, + 282590272U, 282720832U, 282853184U, 282983744U, 283115072U, 283246144U, + 283377344U, 283508416U, 283639744U, 283770304U, 283901504U, 284032576U, + 284163136U, 284294848U, 284426176U, 284556992U, 284687296U, 284819264U, + 284950208U, 285081536U +}; + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libubqhash/dllmain.cpp b/src/Native/libubqhash/dllmain.cpp new file mode 100644 index 000000000..69b58914b --- /dev/null +++ b/src/Native/libubqhash/dllmain.cpp @@ -0,0 +1,19 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/src/Native/libubqhash/endian.h b/src/Native/libubqhash/endian.h new file mode 100644 index 000000000..5b8abf03d --- /dev/null +++ b/src/Native/libubqhash/endian.h @@ -0,0 +1,78 @@ +#pragma once + +#include +#include "compiler.h" + +#if defined(__MINGW32__) || defined(_WIN32) + # define LITTLE_ENDIAN 1234 + # define BYTE_ORDER LITTLE_ENDIAN +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) + # include +#elif defined(__OpenBSD__) || defined(__SVR4) + # include +#elif defined(__APPLE__) +# include +#elif defined( BSD ) && (BSD >= 199103) + # include +#elif defined( __QNXNTO__ ) && defined( __LITTLEENDIAN__ ) + # define LITTLE_ENDIAN 1234 + # define BYTE_ORDER LITTLE_ENDIAN +#elif defined( __QNXNTO__ ) && defined( __BIGENDIAN__ ) + # define BIG_ENDIAN 1234 + # define BYTE_ORDER BIG_ENDIAN +#else +# include +#endif + +#if defined(_WIN32) +#include +#define ethash_swap_u32(input_) _byteswap_ulong(input_) +#define ethash_swap_u64(input_) _byteswap_uint64(input_) +#elif defined(__APPLE__) +#include +#define ethash_swap_u32(input_) OSSwapInt32(input_) +#define ethash_swap_u64(input_) OSSwapInt64(input_) +#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) +#define ethash_swap_u32(input_) bswap32(input_) +#define ethash_swap_u64(input_) bswap64(input_) +#elif defined(__OpenBSD__) +#include +#define ethash_swap_u32(input_) swap32(input_) +#define ethash_swap_u64(input_) swap64(input_) +#else // posix +#include +#define ethash_swap_u32(input_) bswap_32(input_) +#define ethash_swap_u64(input_) bswap_64(input_) +#endif + + +#if LITTLE_ENDIAN == BYTE_ORDER + +#define fix_endian32(dst_ ,src_) dst_ = src_ +#define fix_endian32_same(val_) +#define fix_endian64(dst_, src_) dst_ = src_ +#define fix_endian64_same(val_) +#define fix_endian_arr32(arr_, size_) +#define fix_endian_arr64(arr_, size_) + +#elif BIG_ENDIAN == BYTE_ORDER + +#define fix_endian32(dst_, src_) dst_ = ethash_swap_u32(src_) +#define fix_endian32_same(val_) val_ = ethash_swap_u32(val_) +#define fix_endian64(dst_, src_) dst_ = ethash_swap_u64(src_) +#define fix_endian64_same(val_) val_ = ethash_swap_u64(val_) +#define fix_endian_arr32(arr_, size_) \ + do { \ + for (unsigned i_ = 0; i_ < (size_); ++i_) { \ + arr_[i_] = ethash_swap_u32(arr_[i_]); \ + } \ + } while (0) +#define fix_endian_arr64(arr_, size_) \ + do { \ + for (unsigned i_ = 0; i_ < (size_); ++i_) { \ + arr_[i_] = ethash_swap_u64(arr_[i_]); \ + } \ + } while (0) +#else +# error "endian not supported" +#endif // BYTE_ORDER diff --git a/src/Native/libubqhash/ethash.h b/src/Native/libubqhash/ethash.h new file mode 100644 index 000000000..3a412542f --- /dev/null +++ b/src/Native/libubqhash/ethash.h @@ -0,0 +1,150 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ + +/** @file ethash.h +* @date 2015 +*/ +#pragma once + +#include +#include +#include +#include +#include "compiler.h" + +#define ETHASH_REVISION 23 +#define ETHASH_DATASET_BYTES_INIT 1073741824U // 2**30 +#define ETHASH_DATASET_BYTES_GROWTH 8388608U // 2**23 +#define ETHASH_CACHE_BYTES_INIT 1073741824U // 2**24 +#define ETHASH_CACHE_BYTES_GROWTH 131072U // 2**17 +#define ETHASH_EPOCH_LENGTH 30000U +#define ETHASH_MIX_BYTES 128 +#define ETHASH_HASH_BYTES 64 +#define ETHASH_DATASET_PARENTS 256 +#define ETHASH_CACHE_ROUNDS 3 +#define ETHASH_ACCESSES 64 +#define ETHASH_DAG_MAGIC_NUM_SIZE 8 +#define ETHASH_DAG_MAGIC_NUM 0xFEE1DEADBADDCAFE +#define UBQHASH_UIP1_EPOCH 22 + +#ifdef __cplusplus +extern "C" { +#endif + +/// Type of a seedhash/blockhash e.t.c. +typedef struct ethash_h256 { uint8_t b[32]; } ethash_h256_t; + +// convenience macro to statically initialize an h256_t +// usage: +// ethash_h256_t a = ethash_h256_static_init(1, 2, 3, ... ) +// have to provide all 32 values. If you don't provide all the rest +// will simply be unitialized (not guranteed to be 0) +#define ethash_h256_static_init(...) \ + { {__VA_ARGS__} } + +struct ethash_light; +typedef struct ethash_light* ethash_light_t; +struct ethash_full; +typedef struct ethash_full* ethash_full_t; +typedef int(*ethash_callback_t)(unsigned); + +#pragma pack(push, 1) +typedef struct ethash_return_value { + ethash_h256_t result; + ethash_h256_t mix_hash; + bool success; +} ethash_return_value_t; +#pragma pack(pop) + +/** + * Allocate and initialize a new ethash_light handler + * + * @param block_number The block number for which to create the handler + * @return Newly allocated ethash_light handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes() + */ +ethash_light_t ethash_light_new(uint64_t block_number); +/** + * Frees a previously allocated ethash_light handler + * @param light The light handler to free + */ +void ethash_light_delete(ethash_light_t light); +/** + * Calculate the light client data + * + * @param light The light client handler + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return an object of ethash_return_value_t holding the return values + */ +ethash_return_value_t ethash_light_compute( + ethash_light_t light, + ethash_h256_t const header_hash, + uint64_t nonce +); + +/** + * Allocate and initialize a new ethash_full handler + * + * @param light The light handler containing the cache. + * @param callback A callback function with signature of @ref ethash_callback_t + * It accepts an unsigned with which a progress of DAG calculation + * can be displayed. If all goes well the callback should return 0. + * If a non-zero value is returned then DAG generation will stop. + * Be advised. A progress value of 100 means that DAG creation is + * almost complete and that this function will soon return succesfully. + * It does not mean that the function has already had a succesfull return. + * @return Newly allocated ethash_full handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data() + */ +ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback); + +/** + * Frees a previously allocated ethash_full handler + * @param full The light handler to free + */ +void ethash_full_delete(ethash_full_t full); +/** + * Calculate the full client data + * + * @param full The full client handler + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return An object of ethash_return_value to hold the return value + */ +ethash_return_value_t ethash_full_compute( + ethash_full_t full, + ethash_h256_t const header_hash, + uint64_t nonce +); +/** + * Get a pointer to the full DAG data + */ +void const* ethash_full_dag(ethash_full_t full); +/** + * Get the size of the DAG data + */ +uint64_t ethash_full_dag_size(ethash_full_t full); + +/** + * Calculate the seedhash for a given block number + */ +ethash_h256_t ethash_get_seedhash(uint64_t block_number); + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libubqhash/exports.cpp b/src/Native/libubqhash/exports.cpp new file mode 100644 index 000000000..506cb149c --- /dev/null +++ b/src/Native/libubqhash/exports.cpp @@ -0,0 +1,98 @@ +/* +Copyright 2017 Coin Foundry (coinfoundry.org) +Authors: Oliver Weichhold (oliver@weichhold.com) +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and +associated documentation files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: +The above copyright notice and this permission notice shall be included in all copies or substantial +portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT +LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#include "sha3.h" +#include "internal.h" +#include "ethash.h" + +extern "C" bool ethash_get_default_dirname(char* strbuf, size_t buffsize); + +#ifdef _WIN32 +#define MODULE_API __declspec(dllexport) +#else +#define MODULE_API +#endif + +extern "C" MODULE_API uint64_t ethash_get_datasize_export(uint64_t const block_number) +{ + return ethash_get_datasize(block_number); +} + +extern "C" MODULE_API uint64_t ethash_get_cachesize_export(uint64_t const block_number) +{ + return ethash_get_cachesize(block_number); +} + +extern "C" MODULE_API ethash_light_t ethash_light_new_export(uint64_t block_number) +{ + return ethash_light_new(block_number); +} + +extern "C" MODULE_API void ethash_light_delete_export(ethash_light_t light) +{ + ethash_light_delete(light); +} + +extern "C" MODULE_API void ethash_light_compute_export( + ethash_light_t light, + ethash_h256_t const *header_hash, + uint64_t nonce, + ethash_return_value_t *result) +{ + *result = ethash_light_compute(light, *header_hash, nonce); +} + +extern "C" MODULE_API ethash_full_t ethash_full_new_export(const char *dirname, ethash_light_t light, ethash_callback_t callback) +{ + uint64_t full_size = ethash_get_datasize(light->block_number); + ethash_h256_t seedhash = ethash_get_seedhash(light->block_number); + return ethash_full_new_internal(dirname, seedhash, full_size, light, callback); +} + +extern "C" MODULE_API void ethash_full_delete_export(ethash_full_t full) +{ + ethash_full_delete(full); +} + +extern "C" MODULE_API void ethash_full_compute_export( + ethash_full_t full, + ethash_h256_t const *header_hash, + uint64_t nonce, + ethash_return_value_t *result) +{ + *result = ethash_full_compute(full, *header_hash, nonce); +} + +extern "C" MODULE_API void const* ethash_full_dag_export(ethash_full_t full) +{ + return ethash_full_dag(full); +} + +extern "C" MODULE_API uint64_t ethash_full_dag_size_export(ethash_full_t full) +{ + return ethash_full_dag_size(full); +} + +extern "C" MODULE_API ethash_h256_t ethash_get_seedhash_export(uint64_t block_number) +{ + return ethash_get_seedhash(block_number); +} + +extern "C" MODULE_API bool ethash_get_default_dirname_export(char *buf, size_t buf_size) +{ + return ethash_get_default_dirname(buf, buf_size); +} diff --git a/src/Native/libubqhash/fnv.h b/src/Native/libubqhash/fnv.h new file mode 100644 index 000000000..82cd655c4 --- /dev/null +++ b/src/Native/libubqhash/fnv.h @@ -0,0 +1,43 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: 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. + + cpp-ethereum 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. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file fnv.h +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +#pragma once +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define FNV_PRIME 0x01000193 + +/* The FNV-1 spec multiplies the prime with the input one byte (octet) in turn. + We instead multiply it with the full 32-bit input. + This gives a different result compared to a canonical FNV-1 implementation. +*/ +static inline uint32_t fnv_hash(uint32_t const x, uint32_t const y) +{ + return x * FNV_PRIME ^ y; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libubqhash/internal.c b/src/Native/libubqhash/internal.c new file mode 100644 index 000000000..84a62833b --- /dev/null +++ b/src/Native/libubqhash/internal.c @@ -0,0 +1,557 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file internal.c +* @author Tim Hughes +* @author Matthew Wampler-Doty +* @date 2015 +*/ + +#include +#include +#include +#include +#include +#include "mmap.h" +#include "ethash.h" +#include "fnv.h" +#include "endian.h" +#include "internal.h" +#include "data_sizes.h" +#include "io.h" + +#ifdef WITH_CRYPTOPP + +#include "sha3_cryptopp.h" +#include "blake2_cryptopp.h" + +#else +#include "sha3.h" +#include "blake2.h" +#endif // WITH_CRYPTOPP + +#if defined(_MSC_VER) +#include +#endif + +uint64_t ethash_get_datasize(uint64_t const block_number) +{ + assert(block_number / ETHASH_EPOCH_LENGTH < 2048); + return dag_sizes[block_number / ETHASH_EPOCH_LENGTH]; +} + +uint64_t ethash_get_cachesize(uint64_t const block_number) +{ + assert(block_number / ETHASH_EPOCH_LENGTH < 2048); + return cache_sizes[block_number / ETHASH_EPOCH_LENGTH]; +} + +// Follows Sergio's "STRICT MEMORY HARD HASHING FUNCTIONS" (2014) +// https://bitslog.files.wordpress.com/2013/12/memohash-v0-3.pdf +// SeqMemoHash(s, R, N) +bool static ethash_compute_cache_nodes( + node* const nodes, + uint64_t cache_size, + ethash_h256_t const* seed +) +{ + if (cache_size % sizeof(node) != 0) { + return false; + } + uint32_t const num_nodes = (uint32_t) (cache_size / sizeof(node)); + + SHA3_512(nodes[0].bytes, (uint8_t*)seed, 32); + + for (uint32_t i = 1; i != num_nodes; ++i) { + SHA3_512(nodes[i].bytes, nodes[i - 1].bytes, 64); + } + + for (uint32_t j = 0; j != ETHASH_CACHE_ROUNDS; j++) { + for (uint32_t i = 0; i != num_nodes; i++) { + uint32_t const idx = nodes[i].words[0] % num_nodes; + node data; + data = nodes[(num_nodes - 1 + i) % num_nodes]; + for (uint32_t w = 0; w != NODE_WORDS; ++w) { + data.words[w] ^= nodes[idx].words[w]; + } + SHA3_512(nodes[i].bytes, data.bytes, sizeof(data)); + } + } + + // now perform endian conversion + fix_endian_arr32(nodes->words, num_nodes * NODE_WORDS); + return true; +} + +bool static ethash_compute_cache_nodes_uip1( + node* const nodes, + uint64_t cache_size, + ethash_h256_t const* seed +) +{ + if (cache_size % sizeof(node) != 0) { + return false; + } + uint32_t const num_nodes = (uint32_t) (cache_size / sizeof(node)); + + BLAKE2B_512(nodes[0].bytes, (uint8_t*)seed, 32); + + for (uint32_t i = 1; i != num_nodes; ++i) { + BLAKE2B_512(nodes[i].bytes, nodes[i - 1].bytes, 64); + } + + for (uint32_t j = 0; j != ETHASH_CACHE_ROUNDS; j++) { + for (uint32_t i = 0; i != num_nodes; i++) { + uint32_t const idx = nodes[i].words[0] % num_nodes; + node data; + data = nodes[(num_nodes - 1 + i) % num_nodes]; + for (uint32_t w = 0; w != NODE_WORDS; ++w) { + data.words[w] ^= nodes[idx].words[w]; + } + BLAKE2B_512(nodes[i].bytes, data.bytes, sizeof(data)); + } + } + + // now perform endian conversion + fix_endian_arr32(nodes->words, num_nodes * NODE_WORDS); + return true; +} + +void ethash_calculate_dag_item( + node* const ret, + uint32_t node_index, + ethash_light_t const light +) +{ + uint32_t num_parent_nodes = (uint32_t) (light->cache_size / sizeof(node)); + node const* cache_nodes = (node const *) light->cache; + node const* init = &cache_nodes[node_index % num_parent_nodes]; + memcpy(ret, init, sizeof(node)); + ret->words[0] ^= node_index; + SHA3_512(ret->bytes, ret->bytes, sizeof(node)); +#if defined(_M_X64) && HAVE_SSE2 + __m128i const fnv_prime = _mm_set1_epi32(FNV_PRIME); + __m128i xmm0 = ret->xmm[0]; + __m128i xmm1 = ret->xmm[1]; + __m128i xmm2 = ret->xmm[2]; + __m128i xmm3 = ret->xmm[3]; +#endif + + for (uint32_t i = 0; i != ETHASH_DATASET_PARENTS; ++i) { + uint32_t parent_index = fnv_hash(node_index ^ i, ret->words[i % NODE_WORDS]) % num_parent_nodes; + node const *parent = &cache_nodes[parent_index]; + +#if defined(_M_X64) && HAVE_SSE2 + { + xmm0 = _mm_mullo_epi32(xmm0, fnv_prime); + xmm1 = _mm_mullo_epi32(xmm1, fnv_prime); + xmm2 = _mm_mullo_epi32(xmm2, fnv_prime); + xmm3 = _mm_mullo_epi32(xmm3, fnv_prime); + xmm0 = _mm_xor_si128(xmm0, parent->xmm[0]); + xmm1 = _mm_xor_si128(xmm1, parent->xmm[1]); + xmm2 = _mm_xor_si128(xmm2, parent->xmm[2]); + xmm3 = _mm_xor_si128(xmm3, parent->xmm[3]); + + // have to write to ret as values are used to compute index + ret->xmm[0] = xmm0; + ret->xmm[1] = xmm1; + ret->xmm[2] = xmm2; + ret->xmm[3] = xmm3; + } + #else + { + for (unsigned w = 0; w != NODE_WORDS; ++w) { + ret->words[w] = fnv_hash(ret->words[w], parent->words[w]); + } + } +#endif + } + SHA3_512(ret->bytes, ret->bytes, sizeof(node)); +} + +bool ethash_compute_full_data( + void* mem, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +) +{ + if (full_size % (sizeof(uint32_t) * MIX_WORDS) != 0 || + (full_size % sizeof(node)) != 0) { + return false; + } + uint32_t const max_n = (uint32_t)(full_size / sizeof(node)); + node* full_nodes = mem; + double const progress_change = 1.0f / max_n; + double progress = 0.0f; + // now compute full nodes + for (uint32_t n = 0; n != max_n; ++n) { + if (callback && + n % (max_n / 100) == 0 && + callback((unsigned int)(ceil(progress * 100.0f))) != 0) { + + return false; + } + progress += progress_change; + ethash_calculate_dag_item(&(full_nodes[n]), n, light); + } + return true; +} + +static bool ethash_hash( + ethash_return_value_t* ret, + node const* full_nodes, + ethash_light_t const light, + uint64_t full_size, + ethash_h256_t const header_hash, + uint64_t const nonce +) +{ + if (full_size % MIX_WORDS != 0) { + return false; + } + + // pack hash and nonce together into first 40 bytes of s_mix + assert(sizeof(node) * 8 == 512); + node s_mix[MIX_NODES + 1]; + memcpy(s_mix[0].bytes, &header_hash, 32); + fix_endian64(s_mix[0].double_words[4], nonce); + + // compute sha3-512 hash and replicate across mix + SHA3_512(s_mix->bytes, s_mix->bytes, 40); + fix_endian_arr32(s_mix[0].words, 16); + + node* const mix = s_mix + 1; + for (uint32_t w = 0; w != MIX_WORDS; ++w) { + mix->words[w] = s_mix[0].words[w % NODE_WORDS]; + } + + unsigned const page_size = sizeof(uint32_t) * MIX_WORDS; + unsigned const num_full_pages = (unsigned) (full_size / page_size); + + for (unsigned i = 0; i != ETHASH_ACCESSES; ++i) { + uint32_t const index = fnv_hash(s_mix->words[0] ^ i, mix->words[i % MIX_WORDS]) % num_full_pages; + + for (unsigned n = 0; n != MIX_NODES; ++n) { + node const* dag_node; + if (full_nodes) { + dag_node = &full_nodes[MIX_NODES * index + n]; + } else { + node tmp_node; + ethash_calculate_dag_item(&tmp_node, index * MIX_NODES + n, light); + dag_node = &tmp_node; + } + +#if defined(_M_X64) && HAVE_SSE2 + { + __m128i fnv_prime = _mm_set1_epi32(FNV_PRIME); + __m128i xmm0 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[0]); + __m128i xmm1 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[1]); + __m128i xmm2 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[2]); + __m128i xmm3 = _mm_mullo_epi32(fnv_prime, mix[n].xmm[3]); + mix[n].xmm[0] = _mm_xor_si128(xmm0, dag_node->xmm[0]); + mix[n].xmm[1] = _mm_xor_si128(xmm1, dag_node->xmm[1]); + mix[n].xmm[2] = _mm_xor_si128(xmm2, dag_node->xmm[2]); + mix[n].xmm[3] = _mm_xor_si128(xmm3, dag_node->xmm[3]); + } + #else + { + for (unsigned w = 0; w != NODE_WORDS; ++w) { + mix[n].words[w] = fnv_hash(mix[n].words[w], dag_node->words[w]); + } + } +#endif + } + + } + + // compress mix + for (uint32_t w = 0; w != MIX_WORDS; w += 4) { + uint32_t reduction = mix->words[w + 0]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 1]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 2]; + reduction = reduction * FNV_PRIME ^ mix->words[w + 3]; + mix->words[w / 4] = reduction; + } + + fix_endian_arr32(mix->words, MIX_WORDS / 4); + memcpy(&ret->mix_hash, mix->bytes, 32); + // final Keccak hash + SHA3_256(&ret->result, s_mix->bytes, 64 + 32); // Keccak-256(s + compressed_mix) + return true; +} + +void ethash_quick_hash( + ethash_h256_t* return_hash, + ethash_h256_t const* header_hash, + uint64_t nonce, + ethash_h256_t const* mix_hash +) +{ + uint8_t buf[64 + 32]; + memcpy(buf, header_hash, 32); + fix_endian64_same(nonce); + memcpy(&(buf[32]), &nonce, 8); + SHA3_512(buf, buf, 40); + memcpy(&(buf[64]), mix_hash, 32); + SHA3_256(return_hash, buf, 64 + 32); +} + +ethash_h256_t ethash_get_seedhash(uint64_t block_number) +{ + ethash_h256_t ret; + ethash_h256_reset(&ret); + uint64_t const epochs = block_number / ETHASH_EPOCH_LENGTH; + for (uint32_t i = 0; i < epochs; ++i) + SHA3_256(&ret, (uint8_t*)&ret, 32); + return ret; +} + +bool ethash_quick_check_difficulty( + ethash_h256_t const* header_hash, + uint64_t const nonce, + ethash_h256_t const* mix_hash, + ethash_h256_t const* boundary +) +{ + + ethash_h256_t return_hash; + ethash_quick_hash(&return_hash, header_hash, nonce, mix_hash); + return ethash_check_difficulty(&return_hash, boundary); +} + +ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed, bool uip1) +{ + struct ethash_light *ret; + ret = calloc(sizeof(*ret), 1); + if (!ret) { + return NULL; + } + ret->cache = malloc((size_t)cache_size); + if (!ret->cache) { + goto fail_free_light; + } + node* nodes = (node*)ret->cache; + if (uip1) { + if (!ethash_compute_cache_nodes_uip1(nodes, cache_size, seed)) { + goto fail_free_cache_mem; + } + } else { + if (!ethash_compute_cache_nodes(nodes, cache_size, seed)) { + goto fail_free_cache_mem; + } + } + ret->cache_size = cache_size; + return ret; + +fail_free_cache_mem: + free(ret->cache); +fail_free_light: + free(ret); + return NULL; +} + +ethash_light_t ethash_light_new(uint64_t block_number) +{ + ethash_h256_t seedhash = ethash_get_seedhash(block_number); + ethash_light_t ret; + if (block_number >= ETHASH_EPOCH_LENGTH * UBQHASH_UIP1_EPOCH) { + ret = ethash_light_new_internal(ethash_get_cachesize(block_number), &seedhash, true); + } else { + ret = ethash_light_new_internal(ethash_get_cachesize(block_number), &seedhash, false); + } + ret->block_number = block_number; + return ret; +} + +void ethash_light_delete(ethash_light_t light) +{ + if (light->cache) { + free(light->cache); + } + free(light); +} + +ethash_return_value_t ethash_light_compute_internal( + ethash_light_t light, + uint64_t full_size, + ethash_h256_t const header_hash, + uint64_t nonce +) +{ + ethash_return_value_t ret; + ret.success = true; + if (!ethash_hash(&ret, NULL, light, full_size, header_hash, nonce)) { + ret.success = false; + } + return ret; +} + +ethash_return_value_t ethash_light_compute( + ethash_light_t light, + ethash_h256_t const header_hash, + uint64_t nonce +) +{ + uint64_t full_size = ethash_get_datasize(light->block_number); + return ethash_light_compute_internal(light, full_size, header_hash, nonce); +} + +static bool ethash_mmap(struct ethash_full* ret, FILE* f) +{ + int fd; + char* mmapped_data; + errno = 0; + ret->file = f; + if ((fd = ethash_fileno(ret->file)) == -1) { + return false; + } + mmapped_data= mmap( + NULL, + (size_t)ret->file_size + ETHASH_DAG_MAGIC_NUM_SIZE, + PROT_READ | PROT_WRITE, + MAP_SHARED, + fd, + 0 + ); + if (mmapped_data == MAP_FAILED) { + return false; + } + ret->data = (node*)(mmapped_data + ETHASH_DAG_MAGIC_NUM_SIZE); + return true; +} + +ethash_full_t ethash_full_new_internal( + char const* dirname, + ethash_h256_t const seed_hash, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +) +{ + struct ethash_full* ret; + FILE *f = NULL; + ret = calloc(sizeof(*ret), 1); + if (!ret) { + return NULL; + } + ret->file_size = (size_t)full_size; + switch (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, false)) { + case ETHASH_IO_FAIL: + // ethash_io_prepare will do all ETHASH_CRITICAL() logging in fail case + goto fail_free_full; + case ETHASH_IO_MEMO_MATCH: + if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); + goto fail_close_file; + } + return ret; + case ETHASH_IO_MEMO_SIZE_MISMATCH: + // if a DAG of same filename but unexpected size is found, silently force new file creation + if (ethash_io_prepare(dirname, seed_hash, &f, (size_t)full_size, true) != ETHASH_IO_MEMO_MISMATCH) { + ETHASH_CRITICAL("Could not recreate DAG file after finding existing DAG with unexpected size."); + goto fail_free_full; + } + // fallthrough to the mismatch case here, DO NOT go through match + case ETHASH_IO_MEMO_MISMATCH: + if (!ethash_mmap(ret, f)) { + ETHASH_CRITICAL("mmap failure()"); + goto fail_close_file; + } + break; + } + + if (!ethash_compute_full_data(ret->data, full_size, light, callback)) { + ETHASH_CRITICAL("Failure at computing DAG data."); + goto fail_free_full_data; + } + + // after the DAG has been filled then we finalize it by writting the magic number at the beginning + if (fseek(f, 0, SEEK_SET) != 0) { + ETHASH_CRITICAL("Could not seek to DAG file start to write magic number."); + goto fail_free_full_data; + } + uint64_t const magic_num = ETHASH_DAG_MAGIC_NUM; + if (fwrite(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { + ETHASH_CRITICAL("Could not write magic number to DAG's beginning."); + goto fail_free_full_data; + } + if (fflush(f) != 0) {// make sure the magic number IS there + ETHASH_CRITICAL("Could not flush memory mapped data to DAG file. Insufficient space?"); + goto fail_free_full_data; + } + return ret; + +fail_free_full_data: + // could check that munmap(..) == 0 but even if it did not can't really do anything here + munmap(ret->data, (size_t)full_size); +fail_close_file: + fclose(ret->file); +fail_free_full: + free(ret); + return NULL; +} + +ethash_full_t ethash_full_new(ethash_light_t light, ethash_callback_t callback) +{ + char strbuf[256]; + if (!ethash_get_default_dirname(strbuf, 256)) { + return NULL; + } + uint64_t full_size = ethash_get_datasize(light->block_number); + ethash_h256_t seedhash = ethash_get_seedhash(light->block_number); + return ethash_full_new_internal(strbuf, seedhash, full_size, light, callback); +} + +void ethash_full_delete(ethash_full_t full) +{ + // could check that munmap(..) == 0 but even if it did not can't really do anything here + munmap(full->data, (size_t)full->file_size); + if (full->file) { + fclose(full->file); + } + free(full); +} + +ethash_return_value_t ethash_full_compute( + ethash_full_t full, + ethash_h256_t const header_hash, + uint64_t nonce +) +{ + ethash_return_value_t ret; + ret.success = true; + if (!ethash_hash( + &ret, + (node const*)full->data, + NULL, + full->file_size, + header_hash, + nonce)) { + ret.success = false; + } + return ret; +} + +void const* ethash_full_dag(ethash_full_t full) +{ + return full->data; +} + +uint64_t ethash_full_dag_size(ethash_full_t full) +{ + return full->file_size; +} diff --git a/src/Native/libubqhash/internal.h b/src/Native/libubqhash/internal.h new file mode 100644 index 000000000..9f169a19c --- /dev/null +++ b/src/Native/libubqhash/internal.h @@ -0,0 +1,177 @@ +#pragma once +#include "compiler.h" +#include "endian.h" +#include "ethash.h" +#include + +#if defined(_M_X64) && HAVE_SSE2 +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +// compile time settings +#define NODE_WORDS (64/4) +#define MIX_WORDS (ETHASH_MIX_BYTES/4) +#define MIX_NODES (MIX_WORDS / NODE_WORDS) +#include + +typedef union node { + uint8_t bytes[NODE_WORDS * 4]; + uint32_t words[NODE_WORDS]; + uint64_t double_words[NODE_WORDS / 2]; + +#if defined(_M_X64) && HAVE_SSE2 + __m128i xmm[NODE_WORDS/4]; +#endif + +} node; + +static inline uint8_t ethash_h256_get(ethash_h256_t const* hash, unsigned int i) +{ + return hash->b[i]; +} + +static inline void ethash_h256_set(ethash_h256_t* hash, unsigned int i, uint8_t v) +{ + hash->b[i] = v; +} + +static inline void ethash_h256_reset(ethash_h256_t* hash) +{ + memset(hash, 0, 32); +} + +// Returns if hash is less than or equal to boundary (2^256/difficulty) +static inline bool ethash_check_difficulty( + ethash_h256_t const* hash, + ethash_h256_t const* boundary +) +{ + // Boundary is big endian + for (int i = 0; i < 32; i++) { + if (ethash_h256_get(hash, i) == ethash_h256_get(boundary, i)) { + continue; + } + return ethash_h256_get(hash, i) < ethash_h256_get(boundary, i); + } + return true; +} + +/** + * Difficulty quick check for POW preverification + * + * @param header_hash The hash of the header + * @param nonce The block's nonce + * @param mix_hash The mix digest hash + * @param boundary The boundary is defined as (2^256 / difficulty) + * @return true for succesful pre-verification and false otherwise + */ +bool ethash_quick_check_difficulty( + ethash_h256_t const* header_hash, + uint64_t const nonce, + ethash_h256_t const* mix_hash, + ethash_h256_t const* boundary +); + +struct ethash_light { + void* cache; + uint64_t cache_size; + uint64_t block_number; +}; + +/** + * Allocate and initialize a new ethash_light handler. Internal version + * + * @param cache_size The size of the cache in bytes + * @param seed Block seedhash to be used during the computation of the + * cache nodes + * @return Newly allocated ethash_light handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_cache_nodes() + */ +ethash_light_t ethash_light_new_internal(uint64_t cache_size, ethash_h256_t const* seed, bool uip1); + +/** + * Calculate the light client data. Internal version. + * + * @param light The light client handler + * @param full_size The size of the full data in bytes. + * @param header_hash The header hash to pack into the mix + * @param nonce The nonce to pack into the mix + * @return The resulting hash. + */ +ethash_return_value_t ethash_light_compute_internal( + ethash_light_t light, + uint64_t full_size, + ethash_h256_t const header_hash, + uint64_t nonce +); + +struct ethash_full { + FILE* file; + uint64_t file_size; + node* data; +}; + +/** + * Allocate and initialize a new ethash_full handler. Internal version. + * + * @param dirname The directory in which to put the DAG file. + * @param seedhash The seed hash of the block. Used in the DAG file naming. + * @param full_size The size of the full data in bytes. + * @param cache A cache object to use that was allocated with @ref ethash_cache_new(). + * Iff this function succeeds the ethash_full_t will take memory + * memory ownership of the cache and free it at deletion. If + * not then the user still has to handle freeing of the cache himself. + * @param callback A callback function with signature of @ref ethash_callback_t + * It accepts an unsigned with which a progress of DAG calculation + * can be displayed. If all goes well the callback should return 0. + * If a non-zero value is returned then DAG generation will stop. + * @return Newly allocated ethash_full handler or NULL in case of + * ERRNOMEM or invalid parameters used for @ref ethash_compute_full_data() + */ +ethash_full_t ethash_full_new_internal( + char const* dirname, + ethash_h256_t const seed_hash, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +); + +void ethash_calculate_dag_item( + node* const ret, + uint32_t node_index, + ethash_light_t const cache +); + +void ethash_quick_hash( + ethash_h256_t* return_hash, + ethash_h256_t const* header_hash, + const uint64_t nonce, + ethash_h256_t const* mix_hash +); + +uint64_t ethash_get_datasize(uint64_t const block_number); +uint64_t ethash_get_cachesize(uint64_t const block_number); + +/** + * Compute the memory data for a full node's memory + * + * @param mem A pointer to an ethash full's memory + * @param full_size The size of the full data in bytes + * @param cache A cache object to use in the calculation + * @param callback The callback function. Check @ref ethash_full_new() for details. + * @return true if all went fine and false for invalid parameters + */ +bool ethash_compute_full_data( + void* mem, + uint64_t full_size, + ethash_light_t const light, + ethash_callback_t callback +); + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libubqhash/io.c b/src/Native/libubqhash/io.c new file mode 100644 index 000000000..e73939181 --- /dev/null +++ b/src/Native/libubqhash/io.c @@ -0,0 +1,128 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file io.c + * @author Lefteris Karapetsas + * @date 2015 + */ +#include "io.h" +#include +#include +#include + +int ethash_fseek(FILE* f, size_t offset, int origin) +{ +#ifdef _WIN32 + return _fseeki64(f, offset, origin); +#else + return fseeko(f, offset, origin); +#endif +} + +enum ethash_io_rc ethash_io_prepare( + char const* dirname, + ethash_h256_t const seedhash, + FILE** output_file, + uint64_t file_size, + bool force_create +) +{ + char mutable_name[DAG_MUTABLE_NAME_MAX_SIZE]; + enum ethash_io_rc ret = ETHASH_IO_FAIL; + // reset errno before io calls + errno = 0; + + // assert directory exists + if (!ethash_mkdir(dirname)) { + ETHASH_CRITICAL("Could not create the ethash directory"); + goto end; + } + + ethash_io_mutable_name(ETHASH_REVISION, &seedhash, mutable_name); + char* tmpfile = ethash_io_create_filename(dirname, mutable_name, strlen(mutable_name)); + if (!tmpfile) { + ETHASH_CRITICAL("Could not create the full DAG pathname"); + goto end; + } + + FILE *f; + if (!force_create) { + // try to open the file + f = ethash_fopen(tmpfile, "rb+"); + if (f) { + size_t found_size; + if (!ethash_file_size(f, &found_size)) { + fclose(f); + ETHASH_CRITICAL("Could not query size of DAG file: \"%s\"", tmpfile); + goto free_memo; + } + if (file_size != found_size - ETHASH_DAG_MAGIC_NUM_SIZE) { + fclose(f); + ret = ETHASH_IO_MEMO_SIZE_MISMATCH; + goto free_memo; + } + // compare the magic number, no need to care about endianess since it's local + uint64_t magic_num; + if (fread(&magic_num, ETHASH_DAG_MAGIC_NUM_SIZE, 1, f) != 1) { + // I/O error + fclose(f); + ETHASH_CRITICAL("Could not read from DAG file: \"%s\"", tmpfile); + ret = ETHASH_IO_MEMO_SIZE_MISMATCH; + goto free_memo; + } + if (magic_num != ETHASH_DAG_MAGIC_NUM) { + fclose(f); + ret = ETHASH_IO_MEMO_SIZE_MISMATCH; + goto free_memo; + } + ret = ETHASH_IO_MEMO_MATCH; + goto set_file; + } + } + + // file does not exist, will need to be created + f = ethash_fopen(tmpfile, "wb+"); + if (!f) { + ETHASH_CRITICAL("Could not create DAG file: \"%s\"", tmpfile); + goto free_memo; + } + // make sure it's of the proper size + if (ethash_fseek(f, file_size + ETHASH_DAG_MAGIC_NUM_SIZE - 1, SEEK_SET) != 0) { + fclose(f); + ETHASH_CRITICAL("Could not seek to the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fputc('\n', f) == EOF) { + fclose(f); + ETHASH_CRITICAL("Could not write in the end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + if (fflush(f) != 0) { + fclose(f); + ETHASH_CRITICAL("Could not flush at end of DAG file: \"%s\". Insufficient space?", tmpfile); + goto free_memo; + } + ret = ETHASH_IO_MEMO_MISMATCH; + goto set_file; + + ret = ETHASH_IO_MEMO_MATCH; +set_file: + *output_file = f; +free_memo: + free(tmpfile); +end: + return ret; +} diff --git a/src/Native/libubqhash/io.h b/src/Native/libubqhash/io.h new file mode 100644 index 000000000..45e7a74ab --- /dev/null +++ b/src/Native/libubqhash/io.h @@ -0,0 +1,212 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file io.h + * @author Lefteris Karapetsas + * @date 2015 + */ +#pragma once +#include +#include +#include +#include +#ifdef __cplusplus +#define __STDC_FORMAT_MACROS 1 +#endif +#include +#include "endian.h" +#include "ethash.h" + +#ifdef __cplusplus +extern "C" { +#endif +// Maximum size for mutable part of DAG file name +// 6 is for "full-R", the suffix of the filename +// 10 is for maximum number of digits of a uint32_t (for REVISION) +// 1 is for - and 16 is for the first 16 hex digits for first 8 bytes of +// the seedhash and last 1 is for the null terminating character +// Reference: https://github.com/ethereum/wiki/wiki/Ethash-DAG +#define DAG_MUTABLE_NAME_MAX_SIZE (6 + 10 + 1 + 16 + 1) +/// Possible return values of @see ethash_io_prepare +enum ethash_io_rc { + ETHASH_IO_FAIL = 0, ///< There has been an IO failure + ETHASH_IO_MEMO_SIZE_MISMATCH, ///< DAG with revision/hash match, but file size was wrong. + ETHASH_IO_MEMO_MISMATCH, ///< The DAG file did not exist or there was revision/hash mismatch + ETHASH_IO_MEMO_MATCH, ///< DAG file existed and revision/hash matched. No need to do anything +}; + +// small hack for windows. I don't feel I should use va_args and forward just +// to have this one function properly cross-platform abstracted +#if defined(_WIN32) && !defined(__GNUC__) +#define snprintf(...) sprintf_s(__VA_ARGS__) +#endif + +/** + * Logs a critical error in important parts of ethash. Should mostly help + * figure out what kind of problem (I/O, memory e.t.c.) causes a NULL + * ethash_full_t + */ +#ifdef ETHASH_PRINT_CRITICAL_OUTPUT +#define ETHASH_CRITICAL(...) \ + do \ + { \ + printf("ETHASH CRITICAL ERROR: "__VA_ARGS__); \ + printf("\n"); \ + fflush(stdout); \ + } while (0) +#else +#define ETHASH_CRITICAL(...) +#endif + + /** + * An fseek wrapper for crossplatform 64-bit seek. + * + * @param f The file stream whose fd to get + * @param offset Number of bytes from @a origin + * @param origin Initial position + * @return Current offset or -1 to indicate an error + */ +int ethash_fseek(FILE* f, size_t offset, int origin); + +/** + * Prepares io for ethash + * + * Create the DAG directory and the DAG file if they don't exist. + * + * @param[in] dirname A null terminated c-string of the path of the ethash + * data directory. If it does not exist it's created. + * @param[in] seedhash The seedhash of the current block number, used in the + * naming of the file as can be seen from the spec at: + * https://github.com/ethereum/wiki/wiki/Ethash-DAG + * @param[out] output_file If there was no failure then this will point to an open + * file descriptor. User is responsible for closing it. + * In the case of memo match then the file is open on read + * mode, while on the case of mismatch a new file is created + * on write mode + * @param[in] file_size The size that the DAG file should have on disk + * @param[out] force_create If true then there is no check to see if the file + * already exists + * @return For possible return values @see enum ethash_io_rc + */ +enum ethash_io_rc ethash_io_prepare( + char const* dirname, + ethash_h256_t const seedhash, + FILE** output_file, + uint64_t file_size, + bool force_create +); + +/** + * An fopen wrapper for no-warnings crossplatform fopen. + * + * Msvc compiler considers fopen to be insecure and suggests to use their + * alternative. This is a wrapper for this alternative. Another way is to + * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does + * not sound like a good idea. + * + * @param file_name The path to the file to open + * @param mode Opening mode. Check fopen() + * @return The FILE* or NULL in failure + */ +FILE* ethash_fopen(char const* file_name, char const* mode); + +/** + * An strncat wrapper for no-warnings crossplatform strncat. + * + * Msvc compiler considers strncat to be insecure and suggests to use their + * alternative. This is a wrapper for this alternative. Another way is to + * #define _CRT_SECURE_NO_WARNINGS, but disabling all security warnings does + * not sound like a good idea. + * + * @param des Destination buffer + * @param dest_size Maximum size of the destination buffer. This is the + * extra argument for the MSVC secure strncat + * @param src Souce buffer + * @param count Number of bytes to copy from source + * @return If all is well returns the dest buffer. If there is an + * error returns NULL + */ +char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count); + +/** + * A cross-platform mkdir wrapper to create a directory or assert it's there + * + * @param dirname The full path of the directory to create + * @return true if the directory was created or if it already + * existed + */ +bool ethash_mkdir(char const* dirname); + +/** + * Get a file's size + * + * @param[in] f The open file stream whose size to get + * @param[out] size Pass a size_t by reference to contain the file size + * @return true in success and false if there was a failure + */ +bool ethash_file_size(FILE* f, size_t* ret_size); + +/** + * Get a file descriptor number from a FILE stream + * + * @param f The file stream whose fd to get + * @return Platform specific fd handler + */ +int ethash_fileno(FILE* f); + +/** + * Create the filename for the DAG. + * + * @param dirname The directory name in which the DAG file should reside + * If it does not end with a directory separator it is appended. + * @param filename The actual name of the file + * @param filename_length The length of the filename in bytes + * @return A char* containing the full name. User must deallocate. + */ +char* ethash_io_create_filename( + char const* dirname, + char const* filename, + size_t filename_length +); + +/** + * Gets the default directory name for the DAG depending on the system + * + * The spec defining this directory is here: https://github.com/ethereum/wiki/wiki/Ethash-DAG + * + * @param[out] strbuf A string buffer of sufficient size to keep the + * null termninated string of the directory name + * @param[in] buffsize Size of @a strbuf in bytes + * @return true for success and false otherwise + */ +bool ethash_get_default_dirname(char* strbuf, size_t buffsize); + +static inline bool ethash_io_mutable_name( + uint32_t revision, + ethash_h256_t const* seed_hash, + char* output +) +{ + uint64_t hash = *((uint64_t*)seed_hash); +#if LITTLE_ENDIAN == BYTE_ORDER + hash = ethash_swap_u64(hash); +#endif + return snprintf(output, DAG_MUTABLE_NAME_MAX_SIZE, "full-R%u-%016" PRIx64, revision, hash) >= 0; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libubqhash/io_posix.c b/src/Native/libubqhash/io_posix.c new file mode 100644 index 000000000..5e3b35e61 --- /dev/null +++ b/src/Native/libubqhash/io_posix.c @@ -0,0 +1,111 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file io_posix.c + * @author Lefteris Karapetsas + * @date 2015 + */ + +#include "io.h" +#include +#include +#include +#include +#include +#include +#include +#include + +FILE* ethash_fopen(char const* file_name, char const* mode) +{ + return fopen(file_name, mode); +} + +char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count) +{ + return strlen(dest) + count + 1 <= dest_size ? strncat(dest, src, count) : NULL; +} + +bool ethash_mkdir(char const* dirname) +{ + int rc = mkdir(dirname, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + return rc != -1 || errno == EEXIST; +} + +int ethash_fileno(FILE *f) +{ + return fileno(f); +} + +char* ethash_io_create_filename( + char const* dirname, + char const* filename, + size_t filename_length +) +{ + size_t dirlen = strlen(dirname); + size_t dest_size = dirlen + filename_length + 1; + if (dirname[dirlen] != '/') { + dest_size += 1; + } + char* name = malloc(dest_size); + if (!name) { + return NULL; + } + + name[0] = '\0'; + ethash_strncat(name, dest_size, dirname, dirlen); + if (dirname[dirlen] != '/') { + ethash_strncat(name, dest_size, "/", 1); + } + ethash_strncat(name, dest_size, filename, filename_length); + return name; +} + +bool ethash_file_size(FILE* f, size_t* ret_size) +{ + struct stat st; + int fd; + if ((fd = fileno(f)) == -1 || fstat(fd, &st) != 0) { + return false; + } + *ret_size = st.st_size; + return true; +} + +bool ethash_get_default_dirname(char* strbuf, size_t buffsize) +{ + static const char dir_suffix[] = ".ubqhash/"; + strbuf[0] = '\0'; + char* home_dir = getenv("HOME"); + if (!home_dir || strlen(home_dir) == 0) + { + struct passwd* pwd = getpwuid(getuid()); + if (pwd) + home_dir = pwd->pw_dir; + } + + size_t len = strlen(home_dir); + if (!ethash_strncat(strbuf, buffsize, home_dir, len)) { + return false; + } + if (home_dir[len] != '/') { + if (!ethash_strncat(strbuf, buffsize, "/", 1)) { + return false; + } + } + return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix)); +} diff --git a/src/Native/libubqhash/io_win32.c b/src/Native/libubqhash/io_win32.c new file mode 100644 index 000000000..4827b9dbe --- /dev/null +++ b/src/Native/libubqhash/io_win32.c @@ -0,0 +1,110 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file io_win32.c + * @author Lefteris Karapetsas + * @date 2015 + */ + +#include "io.h" +#include +#include +#include +#include +#include +#include + +FILE* ethash_fopen(char const* file_name, char const* mode) +{ + FILE* f; + return fopen_s(&f, file_name, mode) == 0 ? f : NULL; +} + +char* ethash_strncat(char* dest, size_t dest_size, char const* src, size_t count) +{ + return strncat_s(dest, dest_size, src, count) == 0 ? dest : NULL; +} + +bool ethash_mkdir(char const* dirname) +{ + int rc = _mkdir(dirname); + return rc != -1 || errno == EEXIST; +} + +int ethash_fileno(FILE* f) +{ + return _fileno(f); +} + +char* ethash_io_create_filename( + char const* dirname, + char const* filename, + size_t filename_length +) +{ + size_t dirlen = strlen(dirname); + size_t dest_size = dirlen + filename_length + 1; + if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') { + dest_size += 1; + } + char* name = malloc(dest_size); + if (!name) { + return NULL; + } + + name[0] = '\0'; + ethash_strncat(name, dest_size, dirname, dirlen); + if (dirname[dirlen] != '\\' || dirname[dirlen] != '/') { + ethash_strncat(name, dest_size, "\\", 1); + } + ethash_strncat(name, dest_size, filename, filename_length); + return name; +} + +bool ethash_file_size(FILE* f, size_t* ret_size) +{ +#ifdef _WIN32 + struct _stat64 st; + int fd; + if ((fd = _fileno(f)) == -1 || _fstat64(fd, &st) != 0) { + return false; + } + *ret_size = st.st_size; + return true; +#else + struct _stat st; + int fd; + if ((fd = _fileno(f)) == -1 || _fstat(fd, &st) != 0) { + return false; + } + *ret_size = st.st_size; + return true; +#endif +} + +bool ethash_get_default_dirname(char* strbuf, size_t buffsize) +{ + static const char dir_suffix[] = "Ethash\\"; + strbuf[0] = '\0'; + if (!SUCCEEDED(SHGetFolderPathA(NULL, CSIDL_LOCAL_APPDATA, NULL, 0, (CHAR*)strbuf))) { + return false; + } + if (!ethash_strncat(strbuf, buffsize, "\\", 1)) { + return false; + } + + return ethash_strncat(strbuf, buffsize, dir_suffix, sizeof(dir_suffix)); +} diff --git a/src/Native/libubqhash/libubqhash.sln b/src/Native/libubqhash/libubqhash.sln new file mode 100644 index 000000000..895257b66 --- /dev/null +++ b/src/Native/libubqhash/libubqhash.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31229.75 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmultihash", "libubqhash.vcxproj", "{2DE74E14-BF6D-4046-951B-8EBC8A1BA009}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Debug|x64.ActiveCfg = Debug|x64 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Debug|x64.Build.0 = Debug|x64 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Debug|x86.ActiveCfg = Debug|Win32 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Debug|x86.Build.0 = Debug|Win32 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Release|x64.ActiveCfg = Release|x64 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Release|x64.Build.0 = Release|x64 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Release|x86.ActiveCfg = Release|Win32 + {2DE74E14-BF6D-4046-951B-8EBC8A1BA009}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDE0FE54-030A-4DFD-98A1-952779FB461F} + EndGlobalSection +EndGlobal diff --git a/src/Native/libubqhash/libubqhash.vcxproj b/src/Native/libubqhash/libubqhash.vcxproj new file mode 100644 index 000000000..b8d6360b1 --- /dev/null +++ b/src/Native/libubqhash/libubqhash.vcxproj @@ -0,0 +1,205 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942} + Win32Proj + netmultihashnative + 10.0 + libubqhash + + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + DynamicLibrary + true + v143 + Unicode + + + DynamicLibrary + false + v143 + true + Unicode + + + + + + + + + + + + + + + + + + + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + true + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(ProjectDir)windows\lib\x64;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib32-msvc-14.0;$(LibraryPath) + + + false + $(SolutionDir)\..\..\..\..\boost_1_62_0;$(ProjectDir)..\libethhash\windows\include\libsodium;$(ProjectDir)..\libethhash\windows\include\libsodium;$(IncludePath);$(ProjectDir) + $(SolutionDir)\..\..\..\..\boost_1_62_0\lib64-msvc-14.0;$(LibraryPath) + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + Disabled + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreadedDebug + stdcpp14 + + + Windows + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x86\libsodium.lib;%(AdditionalDependencies) + + + + + + + Level3 + MaxSpeed + true + true + SODIUM_STATIC;_CRT_SECURE_NO_WARNINGS;HAVE_SSE2 + true + MultiThreaded + stdcpp14 + + + Windows + true + true + true + Ws2_32.lib;$(ProjectDir)..\libethhash\windows\lib\x64\libsodium.lib;%(AdditionalDependencies) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Native/libubqhash/mmap.h b/src/Native/libubqhash/mmap.h new file mode 100644 index 000000000..1e226e83f --- /dev/null +++ b/src/Native/libubqhash/mmap.h @@ -0,0 +1,47 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file mmap.h + * @author Lefteris Karapetsas + * @date 2015 + */ +#pragma once +#if defined(__MINGW32__) || defined(_WIN32) +#include + +#define PROT_READ 0x1 +#define PROT_WRITE 0x2 +/* This flag is only available in WinXP+ */ +#ifdef FILE_MAP_EXECUTE +#define PROT_EXEC 0x4 +#else +#define PROT_EXEC 0x0 +#define FILE_MAP_EXECUTE 0 +#endif + +#define MAP_SHARED 0x01 +#define MAP_PRIVATE 0x02 +#define MAP_ANONYMOUS 0x20 +#define MAP_ANON MAP_ANONYMOUS +#define MAP_FAILED ((void *) -1) + +void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset); +void munmap(void* addr, size_t length); +#else // posix, yay! ^_^ +#include +#endif + + diff --git a/src/Native/libubqhash/mmap_win32.c b/src/Native/libubqhash/mmap_win32.c new file mode 100644 index 000000000..293de90fb --- /dev/null +++ b/src/Native/libubqhash/mmap_win32.c @@ -0,0 +1,84 @@ +/* mmap() replacement for Windows + * + * Author: Mike Frysinger + * Placed into the public domain + */ + +/* References: + * CreateFileMapping: http://msdn.microsoft.com/en-us/library/aa366537(VS.85).aspx + * CloseHandle: http://msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx + * MapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366761(VS.85).aspx + * UnmapViewOfFile: http://msdn.microsoft.com/en-us/library/aa366882(VS.85).aspx + */ + +#include +#include +#include "mmap.h" + +#ifdef __USE_FILE_OFFSET64 +# define DWORD_HI(x) (x >> 32) +# define DWORD_LO(x) ((x) & 0xffffffff) +#else +# define DWORD_HI(x) (0) +# define DWORD_LO(x) (x) +#endif + +void* mmap(void* start, size_t length, int prot, int flags, int fd, off_t offset) +{ + if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC)) + return MAP_FAILED; + if (fd == -1) { + if (!(flags & MAP_ANON) || offset) + return MAP_FAILED; + } else if (flags & MAP_ANON) + return MAP_FAILED; + + DWORD flProtect; + if (prot & PROT_WRITE) { + if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE_READWRITE; + else + flProtect = PAGE_READWRITE; + } else if (prot & PROT_EXEC) { + if (prot & PROT_READ) + flProtect = PAGE_EXECUTE_READ; + else if (prot & PROT_EXEC) + flProtect = PAGE_EXECUTE; + } else + flProtect = PAGE_READONLY; + + off_t end = length + offset; + HANDLE mmap_fd, h; + if (fd == -1) + mmap_fd = INVALID_HANDLE_VALUE; + else + mmap_fd = (HANDLE)_get_osfhandle(fd); + h = CreateFileMapping(mmap_fd, NULL, flProtect, 0, 0, NULL); + if (h == NULL) + return MAP_FAILED; + + DWORD dwDesiredAccess; + if (prot & PROT_WRITE) + dwDesiredAccess = FILE_MAP_WRITE; + else + dwDesiredAccess = FILE_MAP_READ; + if (prot & PROT_EXEC) + dwDesiredAccess |= FILE_MAP_EXECUTE; + if (flags & MAP_PRIVATE) + dwDesiredAccess |= FILE_MAP_COPY; + void *ret = MapViewOfFile(h, dwDesiredAccess, DWORD_HI(offset), DWORD_LO(offset), length); + if (ret == NULL) { + ret = MAP_FAILED; + } + // since we are handling the file ourselves with fd, close the Windows Handle here + CloseHandle(h); + return ret; +} + +void munmap(void* addr, size_t length) +{ + UnmapViewOfFile(addr); +} + +#undef DWORD_HI +#undef DWORD_LO diff --git a/src/Native/libubqhash/sha3.c b/src/Native/libubqhash/sha3.c new file mode 100644 index 000000000..e72fe1018 --- /dev/null +++ b/src/Native/libubqhash/sha3.c @@ -0,0 +1,151 @@ +/** libkeccak-tiny +* +* A single-file implementation of SHA-3 and SHAKE. +* +* Implementor: David Leon Gil +* License: CC0, attribution kindly requested. Blame taken too, +* but not liability. +*/ +#include "sha3.h" + +#include +#include +#include +#include + +/******** The Keccak-f[1600] permutation ********/ + +/*** Constants. ***/ +static const uint8_t rho[24] = \ + { 1, 3, 6, 10, 15, 21, + 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, + 62, 18, 39, 61, 20, 44}; +static const uint8_t pi[24] = \ + {10, 7, 11, 17, 18, 3, + 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, + 20, 14, 22, 9, 6, 1}; +static const uint64_t RC[24] = \ + {1ULL, 0x8082ULL, 0x800000000000808aULL, 0x8000000080008000ULL, + 0x808bULL, 0x80000001ULL, 0x8000000080008081ULL, 0x8000000000008009ULL, + 0x8aULL, 0x88ULL, 0x80008009ULL, 0x8000000aULL, + 0x8000808bULL, 0x800000000000008bULL, 0x8000000000008089ULL, 0x8000000000008003ULL, + 0x8000000000008002ULL, 0x8000000000000080ULL, 0x800aULL, 0x800000008000000aULL, + 0x8000000080008081ULL, 0x8000000000008080ULL, 0x80000001ULL, 0x8000000080008008ULL}; + +/*** Helper macros to unroll the permutation. ***/ +#define rol(x, s) (((x) << s) | ((x) >> (64 - s))) +#define REPEAT6(e) e e e e e e +#define REPEAT24(e) REPEAT6(e e e e) +#define REPEAT5(e) e e e e e +#define FOR5(v, s, e) \ + v = 0; \ + REPEAT5(e; v += s;) + +/*** Keccak-f[1600] ***/ +static inline void keccakf(void* state) { + uint64_t* a = (uint64_t*)state; + uint64_t b[5] = {0}; + uint64_t t = 0; + uint8_t x, y; + + for (int i = 0; i < 24; i++) { + // Theta + FOR5(x, 1, + b[x] = 0; + FOR5(y, 5, + b[x] ^= a[x + y]; )) + FOR5(x, 1, + FOR5(y, 5, + a[y + x] ^= b[(x + 4) % 5] ^ rol(b[(x + 1) % 5], 1); )) + // Rho and pi + t = a[1]; + x = 0; + REPEAT24(b[0] = a[pi[x]]; + a[pi[x]] = rol(t, rho[x]); + t = b[0]; + x++; ) + // Chi + FOR5(y, + 5, + FOR5(x, 1, + b[x] = a[y + x];) + FOR5(x, 1, + a[y + x] = b[x] ^ ((~b[(x + 1) % 5]) & b[(x + 2) % 5]); )) + // Iota + a[0] ^= RC[i]; + } +} + +/******** The FIPS202-defined functions. ********/ + +/*** Some helper macros. ***/ + +#define _(S) do { S } while (0) +#define FOR(i, ST, L, S) \ + _(for (size_t i = 0; i < L; i += ST) { S; }) +#define mkapply_ds(NAME, S) \ + static inline void NAME(uint8_t* dst, \ + const uint8_t* src, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } +#define mkapply_sd(NAME, S) \ + static inline void NAME(const uint8_t* src, \ + uint8_t* dst, \ + size_t len) { \ + FOR(i, 1, len, S); \ + } + +mkapply_ds(xorin, dst[i] ^= src[i]) // xorin +mkapply_sd(setout, dst[i] = src[i]) // setout + +#define P keccakf +#define Plen 200 + +// Fold P*F over the full blocks of an input. +#define foldP(I, L, F) \ + while (L >= rate) { \ + F(a, I, rate); \ + P(a); \ + I += rate; \ + L -= rate; \ + } + +/** The sponge-based hash construction. **/ +static inline int hash(uint8_t* out, size_t outlen, + const uint8_t* in, size_t inlen, + size_t rate, uint8_t delim) { + if ((out == NULL) || ((in == NULL) && inlen != 0) || (rate >= Plen)) { + return -1; + } + uint8_t a[Plen] = {0}; + // Absorb input. + foldP(in, inlen, xorin); + // Xor in the DS and pad frame. + a[inlen] ^= delim; + a[rate - 1] ^= 0x80; + // Xor in the last block. + xorin(a, in, inlen); + // Apply P + P(a); + // Squeeze output. + foldP(out, outlen, setout); + setout(a, out, outlen); + memset(a, 0, 200); + return 0; +} + +#define defsha3(bits) \ + int sha3_##bits(uint8_t* out, size_t outlen, \ + const uint8_t* in, size_t inlen) { \ + if (outlen > (bits/8)) { \ + return -1; \ + } \ + return hash(out, outlen, in, inlen, 200 - (bits / 4), 0x01); \ + } + +/*** FIPS202 SHA3 FOFs ***/ +defsha3(256) +defsha3(512) diff --git a/src/Native/libubqhash/sha3.h b/src/Native/libubqhash/sha3.h new file mode 100644 index 000000000..a38006292 --- /dev/null +++ b/src/Native/libubqhash/sha3.h @@ -0,0 +1,31 @@ +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "compiler.h" +#include +#include + +struct ethash_h256; + +#define decsha3(bits) \ + int sha3_##bits(uint8_t*, size_t, uint8_t const*, size_t); + +decsha3(256) +decsha3(512) + +static inline void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t const size) +{ + sha3_256((uint8_t*)ret, 32, data, size); +} + +static inline void SHA3_512(uint8_t* ret, uint8_t const* data, size_t const size) +{ + sha3_512(ret, 64, data, size); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libubqhash/sha3_cryptopp.cpp b/src/Native/libubqhash/sha3_cryptopp.cpp new file mode 100644 index 000000000..519d1405e --- /dev/null +++ b/src/Native/libubqhash/sha3_cryptopp.cpp @@ -0,0 +1,37 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ + +/** @file sha3.cpp +* @author Tim Hughes +* @date 2015 +*/ +#include +#include + +extern "C" { +struct ethash_h256; +typedef struct ethash_h256 ethash_h256_t; +void SHA3_256(ethash_h256_t const* ret, uint8_t const* data, size_t size) +{ + CryptoPP::SHA3_256().CalculateDigest((uint8_t*)ret, data, size); +} + +void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size) +{ + CryptoPP::SHA3_512().CalculateDigest(ret, data, size); +} +} diff --git a/src/Native/libubqhash/sha3_cryptopp.h b/src/Native/libubqhash/sha3_cryptopp.h new file mode 100644 index 000000000..9edc407d5 --- /dev/null +++ b/src/Native/libubqhash/sha3_cryptopp.h @@ -0,0 +1,18 @@ +#pragma once + +#include "compiler.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct ethash_h256; + +void SHA3_256(struct ethash_h256 const* ret, uint8_t const* data, size_t size); +void SHA3_512(uint8_t* const ret, uint8_t const* data, size_t size); + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libubqhash/stdafx.cpp b/src/Native/libubqhash/stdafx.cpp new file mode 100644 index 000000000..bd27597c6 --- /dev/null +++ b/src/Native/libubqhash/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// $safeprojectname$.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/src/Native/libubqhash/stdafx.h b/src/Native/libubqhash/stdafx.h new file mode 100644 index 000000000..f3a07375c --- /dev/null +++ b/src/Native/libubqhash/stdafx.h @@ -0,0 +1,16 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + + + +// TODO: reference additional headers your program requires here diff --git a/src/Native/libubqhash/stdint.h b/src/Native/libubqhash/stdint.h new file mode 100644 index 000000000..4fe0ef9a9 --- /dev/null +++ b/src/Native/libubqhash/stdint.h @@ -0,0 +1,259 @@ +// ISO C9x compliant stdint.h for Microsoft Visual Studio +// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 +// +// Copyright (c) 2006-2013 Alexander Chemeris +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the product nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _MSC_VER // [ +#error "Use this header only with Microsoft Visual C++ compilers!" +#endif // _MSC_VER ] + +#ifndef _MSC_STDINT_H_ // [ +#define _MSC_STDINT_H_ + +#if _MSC_VER > 1000 +#pragma once +#endif + +#if _MSC_VER >= 1600 // [ +#include +#else // ] _MSC_VER >= 1600 [ + +#include + +// For Visual Studio 6 in C++ mode and for many Visual Studio versions when +// compiling for ARM we should wrap include with 'extern "C++" {}' +// or compiler give many errors like this: +// error C2733: second C linkage of overloaded function 'wmemchr' not allowed +#ifdef __cplusplus +extern "C" { +#endif +# include +#ifdef __cplusplus +} +#endif + +// Define _W64 macros to mark types changing their size, like intptr_t. +#ifndef _W64 +# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 +# define _W64 __w64 +# else +# define _W64 +# endif +#endif + + +// 7.18.1 Integer types + +// 7.18.1.1 Exact-width integer types + +// Visual Studio 6 and Embedded Visual C++ 4 doesn't +// realize that, e.g. char has the same size as __int8 +// so we give up on __intX for them. +#if (_MSC_VER < 1300) + typedef signed char int8_t; + typedef signed short int16_t; + typedef signed int int32_t; + typedef unsigned char uint8_t; + typedef unsigned short uint16_t; + typedef unsigned int uint32_t; +#else + typedef signed __int8 int8_t; + typedef signed __int16 int16_t; + typedef signed __int32 int32_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; +#endif +typedef signed __int64 int64_t; +typedef unsigned __int64 uint64_t; + + +// 7.18.1.2 Minimum-width integer types +typedef int8_t int_least8_t; +typedef int16_t int_least16_t; +typedef int32_t int_least32_t; +typedef int64_t int_least64_t; +typedef uint8_t uint_least8_t; +typedef uint16_t uint_least16_t; +typedef uint32_t uint_least32_t; +typedef uint64_t uint_least64_t; + +// 7.18.1.3 Fastest minimum-width integer types +typedef int8_t int_fast8_t; +typedef int16_t int_fast16_t; +typedef int32_t int_fast32_t; +typedef int64_t int_fast64_t; +typedef uint8_t uint_fast8_t; +typedef uint16_t uint_fast16_t; +typedef uint32_t uint_fast32_t; +typedef uint64_t uint_fast64_t; + +// 7.18.1.4 Integer types capable of holding object pointers +#ifdef _WIN64 // [ + typedef signed __int64 intptr_t; + typedef unsigned __int64 uintptr_t; +#else // _WIN64 ][ + typedef _W64 signed int intptr_t; + typedef _W64 unsigned int uintptr_t; +#endif // _WIN64 ] + +// 7.18.1.5 Greatest-width integer types +typedef int64_t intmax_t; +typedef uint64_t uintmax_t; + + +// 7.18.2 Limits of specified-width integer types + +#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 + +// 7.18.2.1 Limits of exact-width integer types +#define INT8_MIN ((int8_t)_I8_MIN) +#define INT8_MAX _I8_MAX +#define INT16_MIN ((int16_t)_I16_MIN) +#define INT16_MAX _I16_MAX +#define INT32_MIN ((int32_t)_I32_MIN) +#define INT32_MAX _I32_MAX +#define INT64_MIN ((int64_t)_I64_MIN) +#define INT64_MAX _I64_MAX +#define UINT8_MAX _UI8_MAX +#define UINT16_MAX _UI16_MAX +#define UINT32_MAX _UI32_MAX +#define UINT64_MAX _UI64_MAX + +// 7.18.2.2 Limits of minimum-width integer types +#define INT_LEAST8_MIN INT8_MIN +#define INT_LEAST8_MAX INT8_MAX +#define INT_LEAST16_MIN INT16_MIN +#define INT_LEAST16_MAX INT16_MAX +#define INT_LEAST32_MIN INT32_MIN +#define INT_LEAST32_MAX INT32_MAX +#define INT_LEAST64_MIN INT64_MIN +#define INT_LEAST64_MAX INT64_MAX +#define UINT_LEAST8_MAX UINT8_MAX +#define UINT_LEAST16_MAX UINT16_MAX +#define UINT_LEAST32_MAX UINT32_MAX +#define UINT_LEAST64_MAX UINT64_MAX + +// 7.18.2.3 Limits of fastest minimum-width integer types +#define INT_FAST8_MIN INT8_MIN +#define INT_FAST8_MAX INT8_MAX +#define INT_FAST16_MIN INT16_MIN +#define INT_FAST16_MAX INT16_MAX +#define INT_FAST32_MIN INT32_MIN +#define INT_FAST32_MAX INT32_MAX +#define INT_FAST64_MIN INT64_MIN +#define INT_FAST64_MAX INT64_MAX +#define UINT_FAST8_MAX UINT8_MAX +#define UINT_FAST16_MAX UINT16_MAX +#define UINT_FAST32_MAX UINT32_MAX +#define UINT_FAST64_MAX UINT64_MAX + +// 7.18.2.4 Limits of integer types capable of holding object pointers +#ifdef _WIN64 // [ +# define INTPTR_MIN INT64_MIN +# define INTPTR_MAX INT64_MAX +# define UINTPTR_MAX UINT64_MAX +#else // _WIN64 ][ +# define INTPTR_MIN INT32_MIN +# define INTPTR_MAX INT32_MAX +# define UINTPTR_MAX UINT32_MAX +#endif // _WIN64 ] + +// 7.18.2.5 Limits of greatest-width integer types +#define INTMAX_MIN INT64_MIN +#define INTMAX_MAX INT64_MAX +#define UINTMAX_MAX UINT64_MAX + +// 7.18.3 Limits of other integer types + +#ifdef _WIN64 // [ +# define PTRDIFF_MIN _I64_MIN +# define PTRDIFF_MAX _I64_MAX +#else // _WIN64 ][ +# define PTRDIFF_MIN _I32_MIN +# define PTRDIFF_MAX _I32_MAX +#endif // _WIN64 ] + +#define SIG_ATOMIC_MIN INT_MIN +#define SIG_ATOMIC_MAX INT_MAX + +#ifndef SIZE_MAX // [ +# ifdef _WIN64 // [ +# define SIZE_MAX _UI64_MAX +# else // _WIN64 ][ +# define SIZE_MAX _UI32_MAX +# endif // _WIN64 ] +#endif // SIZE_MAX ] + +// WCHAR_MIN and WCHAR_MAX are also defined in +#ifndef WCHAR_MIN // [ +# define WCHAR_MIN 0 +#endif // WCHAR_MIN ] +#ifndef WCHAR_MAX // [ +# define WCHAR_MAX _UI16_MAX +#endif // WCHAR_MAX ] + +#define WINT_MIN 0 +#define WINT_MAX _UI16_MAX + +#endif // __STDC_LIMIT_MACROS ] + + +// 7.18.4 Limits of other integer types + +#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 + +// 7.18.4.1 Macros for minimum-width integer constants + +#define INT8_C(val) val##i8 +#define INT16_C(val) val##i16 +#define INT32_C(val) val##i32 +#define INT64_C(val) val##i64 + +#define UINT8_C(val) val##ui8 +#define UINT16_C(val) val##ui16 +#define UINT32_C(val) val##ui32 +#define UINT64_C(val) val##ui64 + +// 7.18.4.2 Macros for greatest-width integer constants +// These #ifndef's are needed to prevent collisions with . +// Check out Issue 9 for the details. +#ifndef INTMAX_C // [ +# define INTMAX_C INT64_C +#endif // INTMAX_C ] +#ifndef UINTMAX_C // [ +# define UINTMAX_C UINT64_C +#endif // UINTMAX_C ] + +#endif // __STDC_CONSTANT_MACROS ] + +#endif // _MSC_VER >= 1600 ] + +#endif // _MSC_STDINT_H_ ] diff --git a/src/Native/libubqhash/targetver.h b/src/Native/libubqhash/targetver.h new file mode 100644 index 000000000..87c0086de --- /dev/null +++ b/src/Native/libubqhash/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/src/Native/libubqhash/util.h b/src/Native/libubqhash/util.h new file mode 100644 index 000000000..c5fc6e55b --- /dev/null +++ b/src/Native/libubqhash/util.h @@ -0,0 +1,47 @@ +/* + This file is part of ethash. + + ethash is free software: 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. + + ethash 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. + + You should have received a copy of the GNU General Public License + along with ethash. If not, see . +*/ +/** @file util.h + * @author Tim Hughes + * @date 2015 + */ +#pragma once +#include +#include "compiler.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +void debugf(char const* str, ...); +#else +#define debugf printf +#endif + +static inline uint32_t min_u32(uint32_t a, uint32_t b) +{ + return a < b ? a : b; +} + +static inline uint32_t clamp_u32(uint32_t x, uint32_t min_, uint32_t max_) +{ + return x < min_ ? min_ : (x > max_ ? max_ : x); +} + +#ifdef __cplusplus +} +#endif diff --git a/src/Native/libubqhash/util_win32.c b/src/Native/libubqhash/util_win32.c new file mode 100644 index 000000000..268e6db05 --- /dev/null +++ b/src/Native/libubqhash/util_win32.c @@ -0,0 +1,38 @@ +/* + This file is part of cpp-ethereum. + + cpp-ethereum is free software: 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. + + cpp-ethereum 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. + + You should have received a copy of the GNU General Public License + along with cpp-ethereum. If not, see . +*/ +/** @file util.c + * @author Tim Hughes + * @date 2015 + */ +#include +#include +#include "util.h" + + +// foward declare without all of Windows.h +__declspec(dllimport) void __stdcall OutputDebugStringA(char const* lpOutputString); + +void debugf(char const* str, ...) +{ + va_list args; + va_start(args, str); + + char buf[1<<16]; + _vsnprintf_s(buf, sizeof(buf), sizeof(buf), str, args); + buf[sizeof(buf)-1] = '\0'; + OutputDebugStringA(buf); +}