public void Crytonote_ConvertBlob() { var blob = "0106e5b3afd505583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b421c0300a401d90101ff9d0106d6d6a88702023c62e43372a58cb588147e20be53a27083f5c522f33c722b082ab7518c48cda280b4c4c32102609ec96e2499ee267d70efefc49f26e330526d3ef455314b7b5ba268a6045f8c80c0fc82aa0202fe5cc0fa56c4277d1a47827edce4725571529d57f33c73ada481ef84c323f30a8090cad2c60e02d88bf5e72a611c8b8464ce29e3b1adbfe1ae163886d9150fe511171cada98fcb80e08d84ddcb0102441915aaf9fbaf70ff454c701a6ae2bd59bb94dc0b888bf7e5d06274ee9238ca80c0caf384a302024078526e2132def44bde2806242652f5944e632f7d94290dd6ee5dda1929f5ee2b016e29f25f07ec2a8df59f0e118a6c9a4b769b745dc0c729071f6e0399d2585745020800000000012e7f76000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000".HexToByteArray(); var result = LibCryptonote.ConvertBlob(blob, 330).ToHexString(); Assert.Equal("0106e5b3afd505583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b421c0300a4487286e262e95b8d2163a0c8b73527e8c9425adbdc4e532cf0ef4241f9ffbe9e01", result); }
public void Cryptonote_ConvertBlob_Should_Match() { var blob = "0105bfdfcecd05583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b420000000001d90101ff9d0106d6d6a88702020a79e36c5f5ac69abb68daa616b70e4dc911ed2edf50133fc121447cc403cd6780b4c4c32102b3adc5521c68a35e2dd1934e30b5fada872b384dbbf8c4e8130e43bd0097b8b680c0fc82aa0202b186f6745517ec23a87df7811849d71914a222c937da3e3a39c7bde6f27d2dc98090cad2c60e02df3a6eed49d05b0163986888ebe7da3fae808a72f3beec97346e0a18a960a7b180e08d84ddcb0102f37220a0c601e2dfe78cfab584cabeecf59079b3b2ee045561fb83ebf67941ba80c0caf384a30202b5e50c62333f3237d497eac37b26bd1217b6996eeb7d45e099b71b0f0b5399162b011c2515730ca7e8bb9b79e177557a1fa8b41e9aee544b25d69dc46f12f66b13f102080000000001ff0d7500".HexToByteArray(); var result = LibCryptonote.ConvertBlob(blob, blob.Length).ToHexString(); var expected = "0105bfdfcecd05583cf50bcc743d04d831d2b119dc94ad88679e359076ee3f18d258ee138b3b4200000000f262fa431f692fa1d8a6e89fb809487a2133dd6fd999d95c664b964df354ac4701"; Assert.Equal(expected, result); }
private string EncodeBlob(uint workerExtraNonce) { Span <byte> blob = stackalloc byte[blobTemplate.Length]; blobTemplate.CopyTo(blob); // inject extranonce (big-endian at the beginning of the reserved area of the blob) var extraNonceBytes = BitConverter.GetBytes(workerExtraNonce.ToBigEndian()); extraNonceBytes.CopyTo(blob.Slice(BlockTemplate.ReservedOffset, extraNonceBytes.Length)); return(LibCryptonote.ConvertBlob(blob, blobTemplate.Length).ToHexString()); }
private string EncodeBlob(uint workerExtraNonce) { // clone template using (var blob = new PooledArraySegment <byte>(_blobTemplate.Length)) { Buffer.BlockCopy(_blobTemplate, 0, blob.Array, 0, _blobTemplate.Length); // inject extranonce (big-endian at the beginning of the reserved area of the blob) var extraNonceBytes = BitConverter.GetBytes(workerExtraNonce.ToBigEndian()); Buffer.BlockCopy(extraNonceBytes, 0, blob.Array, (int)BlockTemplate.ReservedOffset, extraNonceBytes.Length); return(LibCryptonote.ConvertBlob(blob.Array, _blobTemplate.Length).ToHexString()); } }
private string EncodeBlob(uint workerExtraNonce) { // clone template var blob = new byte[blobTemplate.Length]; Buffer.BlockCopy(blobTemplate, 0, blob, 0, blobTemplate.Length); // inject extranonce (big-endian at the beginning of the reserved area of the blob) var extraNonceBytes = BitConverter.GetBytes(workerExtraNonce.ToBigEndian()); Buffer.BlockCopy(extraNonceBytes, 0, blob, (int)BlockTemplate.ReservedOffset, extraNonceBytes.Length); var result = LibCryptonote.ConvertBlob(blob).ToHexString(); return(result); }
public (Share Share, string BlobHex) ProcessShare(string nonce, uint workerExtraNonce, string workerHash, StratumClient worker) { Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(nonce), $"{nameof(nonce)} must not be empty"); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(workerHash), $"{nameof(workerHash)} must not be empty"); Contract.Requires <ArgumentException>(workerExtraNonce != 0, $"{nameof(workerExtraNonce)} must not be empty"); var context = worker.ContextAs <CryptonoteWorkerContext>(); // validate nonce if (!CryptonoteConstants.RegexValidNonce.IsMatch(nonce)) { throw new StratumException(StratumError.MinusOne, "malformed nonce"); } // clone template Span <byte> blob = stackalloc byte[blobTemplate.Length]; blobTemplate.CopyTo(blob); // inject extranonce var extraNonceBytes = BitConverter.GetBytes(workerExtraNonce.ToBigEndian()); extraNonceBytes.CopyTo(blob.Slice(BlockTemplate.ReservedOffset, extraNonceBytes.Length)); // inject nonce var nonceBytes = nonce.HexToByteArray(); nonceBytes.CopyTo(blob.Slice(CryptonoteConstants.BlobNonceOffset, nonceBytes.Length)); // convert var blobConverted = LibCryptonote.ConvertBlob(blob, blobTemplate.Length); if (blobConverted == null) { throw new StratumException(StratumError.MinusOne, "malformed blob"); } Console.WriteLine($"Coin: {coin.Name} Symbol: {coin.Symbol} Family: {coin.Family} Hash: {coin.Hash} Variant: {coin.HashVariant}"); Console.WriteLine("------------------------------------------------------------------------------------------------------------"); Console.WriteLine($"blob Converted: {blobConverted[0]}"); // -------- NEED TO CHANGE ---------->> // determine variant CryptonightVariant variant = CryptonightVariant.VARIANT_0; if (coin.HashVariant != 0) { variant = (CryptonightVariant)coin.HashVariant; } else { switch (coin.Hash) { case CryptonightHashType.Normal: variant = (blobConverted[0] >= 10) ? CryptonightVariant.VARIANT_4 : ((blobConverted[0] >= 8) ? CryptonightVariant.VARIANT_2 : ((blobConverted[0] == 7) ? CryptonightVariant.VARIANT_1 : CryptonightVariant.VARIANT_0)); break; case CryptonightHashType.Lite: variant = CryptonightVariant.VARIANT_1; break; case CryptonightHashType.Heavy: variant = CryptonightVariant.VARIANT_0; break; case CryptonightHashType.RandomX: variant = CryptonightVariant.VARIANT_0; break; default: break; } } // <<------------- Console.WriteLine($""); // hash it Span <byte> headerHash = stackalloc byte[32]; hashFunc(blobConverted, BlockTemplate.SeedHash, headerHash, variant, 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(CryptonoteConstants.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 <byte> blockHash = stackalloc byte[32]; ComputeBlockHash(blobConverted, blockHash); // Fill in block-relevant fields result.IsBlockCandidate = true; result.BlockHash = blockHash.ToHexString(); } return(result, blob.ToHexString()); }
public void Cryptonote_ConvertBlob_Should_Throw_On_Null_Argument() { Assert.Throws <ArgumentNullException>(() => LibCryptonote.ConvertBlob(null, 0)); }
public (Share Share, string BlobHex, string BlobHash) ProcessShare(string nonce, uint workerExtraNonce, string workerHash, StratumClient worker) { Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(nonce), $"{nameof(nonce)} must not be empty"); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(workerHash), $"{nameof(workerHash)} must not be empty"); Contract.Requires <ArgumentException>(workerExtraNonce != 0, $"{nameof(workerExtraNonce)} must not be empty"); var context = worker.GetContextAs <MoneroWorkerContext>(); // validate nonce if (!MoneroConstants.RegexValidNonce.IsMatch(nonce)) { throw new StratumException(StratumError.MinusOne, "malformed nonce"); } // clone template using (var blob = new PooledArraySegment <byte>(blobTemplate.Length)) { Buffer.BlockCopy(blobTemplate, 0, blob.Array, 0, blobTemplate.Length); // inject extranonce var extraNonceBytes = BitConverter.GetBytes(workerExtraNonce.ToBigEndian()); Buffer.BlockCopy(extraNonceBytes, 0, blob.Array, (int)BlockTemplate.ReservedOffset, extraNonceBytes.Length); // inject nonce var nonceBytes = nonce.HexToByteArray(); Buffer.BlockCopy(nonceBytes, 0, blob.Array, MoneroConstants.BlobNonceOffset, nonceBytes.Length); // convert var blobConverted = LibCryptonote.ConvertBlob(blob.Array, blobTemplate.Length); if (blobConverted == null) { throw new StratumException(StratumError.MinusOne, "malformed blob"); } // hash it using (var hashSeg = hashSlow(blobConverted)) { var hash = hashSeg.ToHexString(); if (hash != workerHash) { throw new StratumException(StratumError.MinusOne, "bad hash"); } // check difficulty var headerValue = hashSeg.ToBigInteger(); var shareDiff = (double)new BigRational(MoneroConstants.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})"); } } using (var blockHash = ComputeBlockHash(blobConverted)) { var result = new Share { BlockHeight = BlockTemplate.Height, IsBlockCandidate = isBlockCandidate, BlockHash = blockHash.ToHexString(), Difficulty = stratumDifficulty, }; var blobHex = blob.ToHexString(); var blobHash = blockHash.ToHexString(); return(result, blobHex, blobHash); } } } }
public MoneroShare ProcessShare(string nonce, uint workerExtraNonce, string workerHash, double stratumDifficulty) { Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(nonce), $"{nameof(nonce)} must not be empty"); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(workerHash), $"{nameof(workerHash)} must not be empty"); Contract.Requires <ArgumentException>(extraNonce != 0, $"{nameof(extraNonce)} must not be empty"); // validate nonce if (!MoneroConstants.RegexValidNonce.IsMatch(nonce)) { throw new StratumException(StratumError.MinusOne, "malformed nonce"); } // clone template var blob = new byte[blobTemplate.Length]; Buffer.BlockCopy(blobTemplate, 0, blob, 0, blobTemplate.Length); // inject extranonce var extraNonceBytes = BitConverter.GetBytes(workerExtraNonce.ToBigEndian()); Buffer.BlockCopy(extraNonceBytes, 0, blob, (int)BlockTemplate.ReservedOffset, extraNonceBytes.Length); // inject nonce var nonceBytes = nonce.HexToByteArray(); Buffer.BlockCopy(nonceBytes, 0, blob, MoneroConstants.BlobNonceOffset, nonceBytes.Length); // convert var blobConverted = LibCryptonote.ConvertBlob(blob); if (blobConverted == null) { throw new StratumException(StratumError.MinusOne, "malformed blob"); } // hash it var hashBytes = LibCryptonote.CryptonightHashSlow(blobConverted); var hash = hashBytes.ToHexString(); if (hash != workerHash) { throw new StratumException(StratumError.MinusOne, "bad hash"); } // check difficulty var headerValue = new System.Numerics.BigInteger(hashBytes); var shareDiff = (double)new BigRational(MoneroConstants.Diff1b, headerValue); var ratio = shareDiff / stratumDifficulty; // test if share meets at least workers current difficulty if (ratio < 0.99) { throw new StratumException(StratumError.LowDifficultyShare, $"low difficulty share ({shareDiff})"); } // valid share, check if the share also meets the much harder block difficulty (block candidate) var isBlockCandidate = shareDiff >= BlockTemplate.Difficulty; var result = new MoneroShare { BlockHeight = BlockTemplate.Height, IsBlockCandidate = isBlockCandidate, BlobHex = blob.ToHexString(), BlobHash = ComputeBlockHash(blobConverted).ToHexString() }; return(result); }
public (Share Share, string BlobHex, string BlobHash) ProcessShare(string nonce, uint workerExtraNonce, string workerHash, StratumClient worker) { Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(nonce), $"{nameof(nonce)} must not be empty"); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(workerHash), $"{nameof(workerHash)} must not be empty"); Contract.Requires <ArgumentException>(workerExtraNonce != 0, $"{nameof(workerExtraNonce)} must not be empty"); var context = worker.ContextAs <MoneroWorkerContext>(); // validate nonce if (!MoneroConstants.RegexValidNonce.IsMatch(nonce)) { throw new StratumException(StratumError.MinusOne, "malformed nonce"); } // clone template Span <byte> blob = stackalloc byte[blobTemplate.Length]; blobTemplate.CopyTo(blob); // inject extranonce var extraNonceBytes = BitConverter.GetBytes(workerExtraNonce.ToBigEndian()); extraNonceBytes.CopyTo(blob.Slice(BlockTemplate.ReservedOffset, extraNonceBytes.Length)); // inject nonce var nonceBytes = nonce.HexToByteArray(); nonceBytes.CopyTo(blob.Slice(MoneroConstants.BlobNonceOffset, nonceBytes.Length)); // convert var blobConverted = LibCryptonote.ConvertBlob(blob, blobTemplate.Length); if (blobConverted == null) { throw new StratumException(StratumError.MinusOne, "malformed blob"); } // hash it Span <byte> headerHash = stackalloc byte[32]; switch (coin) { case CoinType.AEON: LibCryptonight.CryptonightLight(blobConverted, headerHash, 0); break; case CoinType.XMR: var variant = blobConverted[0] >= 7 ? blobConverted[0] - 6 : 0; LibCryptonight.Cryptonight(blobConverted, headerHash, variant); break; default: LibCryptonight.Cryptonight(blobConverted, headerHash, 0); break; } 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(MoneroConstants.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})"); } } // Compute block hash Span <byte> blockHash = stackalloc byte[32]; ComputeBlockHash(blobConverted, blockHash); var result = new Share { BlockHeight = BlockTemplate.Height, IsBlockCandidate = isBlockCandidate, BlockHash = blockHash.ToHexString(), Difficulty = stratumDifficulty, }; var blobHex = blob.ToHexString(); var blobHash = blockHash.ToHexString(); return(result, blobHex, blobHash); }