diff --git a/examples/waglayla_pool.json b/examples/waglayla_pool.json new file mode 100644 index 0000000000..255a51eda6 --- /dev/null +++ b/examples/waglayla_pool.json @@ -0,0 +1,129 @@ +{ + "logging": { + "level": "debug", + "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": "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", + "createPoolStats": true, + "migrateToLatest": true + } + }, + "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": "wala1", + "enabled": true, + "coin": "waglayla", + "address": "waglayla:qpy5wlu5mxpq86cefnvfylv7p8emuhttprs5dqm8mwn3ynz2a7zags93a8g05", + "rewardRecipients": [ + { + "type": "op", + "address": "waglayla:qpy5wlu5mxpq86cefnvfylv7p8emuhttprs5dqm8mwn3ynz2a7zags93a8g05", + "percentage": 1 + } + ], + "protobufWalletRpcServiceName": "waglaylawalletd.waglaylawalletd", + "enableAsicBoost": true, + "clientConnectionTimeout": 600, + "banning": { + "enabled": true, + "time": 600, + "invalidPercent": 50, + "checkThreshold": 50 + }, + "ports": { + "3094": { + "listenAddress": "0.0.0.0", + "difficulty": 4, + "varDiff": { + "minDiff": 2, + "maxDiff": null, + "targetTime": 15, + "retargetTime": 90, + "variancePercent": 100, + "maxDelta": 512 + } + } + }, + "daemons": [ + { + "host": "127.0.0.1", + "port": 12110, + "user": null, + "password": null + }, + { + "host": "127.0.0.1", + "port": 8082, + "user": null, + "password": null, + "category": "wallet" + } + ], + "paymentProcessing": { + "enabled": true, + "walletPassword": "", + "minimumPayment": 1, + "versionEnablingMaxFee": "v0.12.18-rc5", + "maxFee": 200000, + "payoutScheme": "PPLNS", + "payoutSchemeConfig": { + "factor": 0.5 + } + } + }] + } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/Custom/Waglayla/WaglaylaJob.cs b/src/Miningcore/Blockchain/Kaspa/Custom/Waglayla/WaglaylaJob.cs index d37c196c60..e1791ebd13 100644 --- a/src/Miningcore/Blockchain/Kaspa/Custom/Waglayla/WaglaylaJob.cs +++ b/src/Miningcore/Blockchain/Kaspa/Custom/Waglayla/WaglaylaJob.cs @@ -1,4 +1,4 @@ -using System; +using System.Text; using System.Numerics; using Miningcore.Crypto; using Miningcore.Crypto.Hashing.Algorithms; @@ -7,98 +7,80 @@ using Miningcore.Util; using NBitcoin; -namespace Miningcore.Blockchain.Kaspa.Custom.Waglayla; +namespace Miningcore.Blockchain.Kaspa.Custom.WagLayla; -public class WaglaylaJob: KaspaJob { - protected Blake3IHash blake3Hasher; - protected Sha3_256 sha3_256Hasher; - - public WaglaylaJob(IHashAlgorithm customBlockHeaderHasher, IHashAlgorithm customCoinbaseHasher, IHashAlgorithm customShareHasher): base(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher) { - this.blake3Hasher = new Blake3IHash(); - this.sha3_256Hasher = new Sha3_256(); - } - - private Span MatrixMultiply(Span input) +public class WagLaylaJob : KaspaJobAltKHeavy { - // Example placeholder matrix operation - byte[,] matrix = { - { 1, 2, 3, 4 }, - { 5, 6, 7, 8 }, - { 9, 10, 11, 12 }, - { 13, 14, 15, 16 } - }; - - byte[] result = new byte[32]; - for (int i = 0; i < 32; i++) + protected Blake3IHash blake3Hasher; + protected Sha3_256 sha3_256Hasher; + + public WagLaylaJob(IHashAlgorithm customBlockHeaderHasher, IHashAlgorithm customCoinbaseHasher, IHashAlgorithm customShareHasher) + : base(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher) { - result[i] = 0; - for (int j = 0; j < 32; j++) - { - result[i] ^= (byte)(input[j] * matrix[i % 4, j % 4]); // Example multiplication - } + this.blake3Hasher = new Blake3IHash(); + this.sha3_256Hasher = new Sha3_256(); } - return result.AsSpan(); -} - - protected override Share ProcessShareInternal(StratumConnection worker, string nonce) { - var context = worker.ContextAs < KaspaWorkerContext > (); - - BlockTemplate.Header.Nonce = Convert.ToUInt64(nonce, 16); - - var prePowHashBytes = SerializeHeader(BlockTemplate.Header, true); - Span < byte > blake3Bytes = stackalloc byte[32]; - blake3Hasher.Digest(prePowHashBytes, blake3Bytes); + protected override Share ProcessShareInternal(StratumConnection worker, string nonce) + { + var context = worker.ContextAs(); - Span < byte > sha3Bytes = stackalloc byte[32]; - sha3_256Hasher.Digest(blake3Bytes, sha3Bytes); + BlockTemplate.Header.Nonce = Convert.ToUInt64(nonce, 16); - Span < byte > matrixResult = MatrixMultiply(sha3Bytes); + var prePowHashBytes = SerializeHeader(BlockTemplate.Header, true); + var coinbaseBytes = SerializeCoinbase(prePowHashBytes, BlockTemplate.Header.Timestamp, BlockTemplate.Header.Nonce); - Span < byte > waglaylaHash = stackalloc byte[32]; - blake3Hasher.Digest(matrixResult, waglaylaHash); + Span sha3_256Bytes = stackalloc byte[32]; + sha3_256Hasher.Digest(coinbaseBytes, sha3_256Bytes); - var targetHashCoinbaseBytes = new Target(new BigInteger(waglaylaHash.ToNewReverseArray(), true, true)); - var hashCoinbaseBytesValue = targetHashCoinbaseBytes.ToUInt256(); + Span hashCoinbaseBytes = stackalloc byte[32]; + shareHasher.Digest(ComputeCoinbase(prePowHashBytes, sha3_256Bytes), hashCoinbaseBytes); - var shareDiff = (double) new BigRational(KaspaConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * shareMultiplier; + var targetHashCoinbaseBytes = new Target(new BigInteger(hashCoinbaseBytes.ToNewReverseArray(), true, true)); + var hashCoinbaseBytesValue = targetHashCoinbaseBytes.ToUInt256(); - // diff check - var stratumDifficulty = context.Difficulty; - var ratio = shareDiff / stratumDifficulty; + var shareDiff = (double) new BigRational(KaspaConstants.Diff1b, targetHashCoinbaseBytes.ToBigInteger()) * shareMultiplier; - // check if the share meets the much harder block difficulty (block candidate) - var isBlockCandidate = hashCoinbaseBytesValue <= blockTargetValue; - //var isBlockCandidate = true; + // diff check + var stratumDifficulty = context.Difficulty; + var ratio = shareDiff / stratumDifficulty; - // 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; + // check if the share meets the much harder block difficulty (block candidate) + var isBlockCandidate = hashCoinbaseBytesValue <= blockTargetValue; - if (ratio < 0.99) - throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); + // 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})"); + } - // use previous difficulty - stratumDifficulty = context.PreviousDifficulty.Value; - } else - throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); - } + var result = new Share + { + BlockHeight = (long) BlockTemplate.Header.DaaScore, + NetworkDifficulty = Difficulty, + Difficulty = context.Difficulty / shareMultiplier + }; - var result = new Share { - BlockHeight = (long) BlockTemplate.Header.DaaScore, - NetworkDifficulty = Difficulty, - Difficulty = context.Difficulty / shareMultiplier - }; + if(isBlockCandidate) + { + var hashBytes = SerializeHeader(BlockTemplate.Header, false); - if (isBlockCandidate) { - var hashBytes = SerializeHeader(BlockTemplate.Header, false); + result.IsBlockCandidate = true; + result.BlockHash = hashBytes.ToHexString(); + } - result.IsBlockCandidate = true; - result.BlockHash = hashBytes.ToHexString(); + return result; } - - return result; - } } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaJob.cs b/src/Miningcore/Blockchain/Kaspa/KaspaJob.cs index ad64a1e77c..ad4893e186 100644 --- a/src/Miningcore/Blockchain/Kaspa/KaspaJob.cs +++ b/src/Miningcore/Blockchain/Kaspa/KaspaJob.cs @@ -387,4 +387,54 @@ public virtual void Init(kaspad.RpcBlock blockTemplate, string jobId, double sha blockTemplate.Header.Timestamp, }; } +} + +public class KaspaJobAltKHeavy : KaspaJob +{ + public KaspaJobAltKHeavy(IHashAlgorithm customBlockHeaderHasher, IHashAlgorithm customCoinbaseHasher, IHashAlgorithm customShareHasher) + : base(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher) + { + } + + protected override Span ComputeCoinbase(Span prePowHash, Span data) + { + ushort[][] matrix = GenerateMatrix(prePowHash); + byte[] scratch = data.ToArray(); // Create a copy to work with + + // Convert bytes to nibbles + ushort[] v = new ushort[64]; + for (int i = 0; i < 16; i++) + { + v[i * 4] = (ushort)(scratch[i * 2] >> 4); + v[i * 4 + 1] = (ushort)(scratch[i * 2] & 0x0F); + v[i * 4 + 2] = (ushort)(scratch[i * 2 + 1] >> 4); + v[i * 4 + 3] = (ushort)(scratch[i * 2 + 1] & 0x0F); + } + + // Perform matrix multiplication with XOR folding + for (int i = 0; i < 16; i++) + { + ushort sum1 = 0, sum2 = 0, sum3 = 0, sum4 = 0; + + for (int j = 0; j < 64; j++) + { + sum1 += (ushort)(matrix[4 * i][j] * v[j]); + sum2 += (ushort)(matrix[4 * i + 1][j] * v[j]); + sum3 += (ushort)(matrix[4 * i + 2][j] * v[j]); + sum4 += (ushort)(matrix[4 * i + 3][j] * v[j]); + } + + // XOR folding of sums + sum1 = (ushort)((sum1 & 0xF) ^ ((sum1 >> 4) & 0xF) ^ ((sum1 >> 8) & 0xF)); + sum2 = (ushort)((sum2 & 0xF) ^ ((sum2 >> 4) & 0xF) ^ ((sum2 >> 8) & 0xF)); + sum3 = (ushort)((sum3 & 0xF) ^ ((sum3 >> 4) & 0xF) ^ ((sum3 >> 8) & 0xF)); + sum4 = (ushort)((sum4 & 0xF) ^ ((sum4 >> 4) & 0xF) ^ ((sum4 >> 8) & 0xF)); + + // XOR with original data + scratch[i * 2] ^= (byte)(((byte)sum1 << 4) | (byte)sum2); + scratch[i * 2 + 1] ^= (byte)(((byte)sum3 << 4) | (byte)sum4); + } + + return scratch; + } } \ No newline at end of file diff --git a/src/Miningcore/Blockchain/Kaspa/KaspaJobManager.cs b/src/Miningcore/Blockchain/Kaspa/KaspaJobManager.cs index 5465d13e9c..54b39d4a85 100644 --- a/src/Miningcore/Blockchain/Kaspa/KaspaJobManager.cs +++ b/src/Miningcore/Blockchain/Kaspa/KaspaJobManager.cs @@ -18,7 +18,7 @@ using Miningcore.Blockchain.Kaspa.Custom.Karlsencoin; using Miningcore.Blockchain.Kaspa.Custom.Pyrin; using Miningcore.Blockchain.Kaspa.Custom.Spectre; -using Miningcore.Blockchain.Kaspa.Custom.Waglayla; +using Miningcore.Blockchain.Kaspa.Custom.WagLayla; using NLog; using Miningcore.Configuration; using Miningcore.Crypto; @@ -345,15 +345,19 @@ private KaspaJob CreateJob(ulong blockHeight) return new SpectreJob(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher); case "WALA": if(customBlockHeaderHasher is not Blake3IHash) - customBlockHeaderHasher = new Blake3IHash(); + { + string coinbaseBlockHash = KaspaConstants.CoinbaseBlockHash; + byte[] hashBytes = Encoding.UTF8.GetBytes(coinbaseBlockHash.PadRight(32, '\0')).Take(32).ToArray(); + customBlockHeaderHasher = new Blake3IHash(hashBytes); + } - if(customCoinbaseHasher is not Sha3_256) - customCoinbaseHasher = new Sha3_256(); + if(customCoinbaseHasher is not Blake3IHash) + customCoinbaseHasher = new Blake3IHash(); if(customShareHasher is not Blake3IHash) customShareHasher = new Blake3IHash(); - return new WaglaylaJob(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher); + return new WagLaylaJob(customBlockHeaderHasher, customCoinbaseHasher, customShareHasher); } diff --git a/src/Miningcore/coins.json b/src/Miningcore/coins.json index b1186982fa..0f3bee8e52 100644 --- a/src/Miningcore/coins.json +++ b/src/Miningcore/coins.json @@ -6538,15 +6538,15 @@ "explorerAccountLink": "https://explorer.spectre-network.org/addresses/{0}" }, "waglayla": { - "name": "Waglayla", - "canonicalName": "Waglayla", + "name": "WagLayla", + "canonicalName": "WagLayla", "symbol": "WALA", "family": "kaspa", "website": "https://waglayla.com/", - "market": "", - "twitter": "", - "telegram": "", - "discord": "", + "market": "https://www.coingecko.com/en/coins/waglayla", + "twitter": "https://x.com/WagLayla", + "telegram": "https://t.me/waglayla", + "discord": "https://discord.gg/a2wcdDYds4", "addressBech32Prefix": "waglayla", "addressBech32PrefixDevnet": "waglayladev", "addressBech32PrefixSimnet": "waglaylasim",