public void Configure(DaemonEndpointConfig[] endPoints, string digestAuthRealm = null) { Contract.RequiresNonNull(endPoints, nameof(endPoints)); Contract.Requires <ArgumentException>(endPoints.Length > 0, $"{nameof(endPoints)} must not be empty"); this.endPoints = endPoints; // create one HttpClient instance per endpoint that carries the associated credentials httpClients = endPoints.ToDictionary(endpoint => endpoint, endpoint => { if (string.IsNullOrEmpty(endpoint.User) || !endpoint.DigestAuth) { return(defaultHttpClient); } return(new HttpClient(new SocketsHttpHandler { AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip, Credentials = new NetworkCredential(endpoint.User, endpoint.Password), PreAuthenticate = true, SslOptions = new SslClientAuthenticationOptions { RemoteCertificateValidationCallback = ((sender, certificate, chain, errors) => true), } })); }); }
/// <summary> /// Executes the request against all configured demons and returns their responses as an array /// </summary> /// <typeparam name="TResponse"></typeparam> /// <param name="method"></param> /// <param name="payload"></param> /// <returns></returns> public async Task <DaemonResponse <TResponse>[]> ExecuteCmdAllAsync <TResponse>(ILogger logger, string method, object payload = null, JsonSerializerSettings payloadJsonSerializerSettings = null) where TResponse : class { Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(method), $"{nameof(method)} must not be empty"); logger.LogInvoke(new[] { "\"" + method + "\"" }); var tasks = endPoints.Select(endPoint => BuildRequestTask(logger, endPoint, method, payload, CancellationToken.None, payloadJsonSerializerSettings)).ToArray(); try { await Task.WhenAll(tasks); } catch (Exception) { // ignored } var results = tasks.Select((x, i) => MapDaemonResponse <TResponse>(i, x)) .ToArray(); return(results); }
public CryptonoteJob(GetBlockTemplateResponse blockTemplate, byte[] instanceId, string jobId, PoolConfig poolConfig, ClusterConfig clusterConfig, string prevHash) { Contract.RequiresNonNull(blockTemplate, nameof(blockTemplate)); Contract.RequiresNonNull(poolConfig, nameof(poolConfig)); Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig)); Contract.RequiresNonNull(instanceId, nameof(instanceId)); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(jobId), $"{nameof(jobId)} must not be empty"); coin = poolConfig.Template.As <CryptonoteCoinTemplate>(); BlockTemplate = blockTemplate; PrepareBlobTemplate(instanceId); PrevHash = prevHash; switch (coin.Hash) { case CryptonightHashType.Normal: hashFunc = LibCryptonight.Cryptonight; break; case CryptonightHashType.Lite: hashFunc = LibCryptonight.CryptonightLight; break; case CryptonightHashType.Heavy: hashFunc = LibCryptonight.CryptonightHeavy; break; } }
public bool ValidateAddress(string address) { Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(address), $"{nameof(address)} must not be empty"); var addressPrefix = LibCryptonote.DecodeAddress(address); var addressIntegratedPrefix = LibCryptonote.DecodeIntegratedAddress(address); var coin = poolConfig.Template.As <CryptonoteCoinTemplate>(); switch (networkType) { case CryptonoteNetworkType.Main: if (addressPrefix != coin.AddressPrefix && addressIntegratedPrefix != coin.AddressPrefixIntegrated) { return(false); } break; case CryptonoteNetworkType.Test: if (addressPrefix != coin.AddressPrefixTestnet && addressIntegratedPrefix != coin.AddressPrefixIntegratedTestnet) { return(false); } break; } return(true); }
public virtual (Share Share, string BlockHex) ProcessShare(StratumClient worker, string extraNonce2, string nTime, string nonce, string versionBits = null) { Contract.RequiresNonNull(worker, nameof(worker)); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(extraNonce2), $"{nameof(extraNonce2)} must not be empty"); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(nTime), $"{nameof(nTime)} must not be empty"); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(nonce), $"{nameof(nonce)} must not be empty"); var context = worker.ContextAs <BitcoinWorkerContext>(); // validate nTime if (nTime.Length != 8) { throw new StratumException(StratumError.Other, "incorrect size of ntime"); } var nTimeInt = uint.Parse(nTime, NumberStyles.HexNumber); if (nTimeInt < BlockTemplate.CurTime || nTimeInt > ((DateTimeOffset)clock.Now).ToUnixTimeSeconds() + 7200) { throw new StratumException(StratumError.Other, "ntime out of range"); } // validate nonce if (nonce.Length != 8) { throw new StratumException(StratumError.Other, "incorrect size of nonce"); } var nonceInt = uint.Parse(nonce, NumberStyles.HexNumber); // validate version-bits (overt ASIC boost) uint versionBitsInt = 0; if (context.VersionRollingMask.HasValue && versionBits != null) { versionBitsInt = uint.Parse(versionBits, NumberStyles.HexNumber); // enforce that only bits covered by current mask are changed by miner if ((versionBitsInt & ~context.VersionRollingMask.Value) != 0) { throw new StratumException(StratumError.Other, "rolling-version mask violation"); } } // dupe check if (!RegisterSubmit(context.ExtraNonce1, extraNonce2, nTime, nonce)) { throw new StratumException(StratumError.DuplicateShare, "duplicate share"); } return(ProcessShareInternal(worker, extraNonce2, nTimeInt, nonceInt, versionBitsInt)); }
public bool ValidateAddress(string address) { Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(address), $"{nameof(address)} must not be empty"); if (EthereumConstants.ZeroHashPattern.IsMatch(address) || !EthereumConstants.ValidAddressPattern.IsMatch(address)) { return(false); } return(true); }
public void Ban(IPAddress address, TimeSpan duration) { Contract.RequiresNonNull(address, nameof(address)); Contract.Requires <ArgumentException>(duration.TotalMilliseconds > 0, $"{nameof(duration)} must not be empty"); // don't ban 127.0.0.1 if (address.Equals(IPAddress.Loopback) || address.Equals(IPAddress.IPv6Loopback)) { return; } cache.Set(address.ToString(), string.Empty, duration); }
/// <summary> /// Executes the request against all configured demons and returns the first successful response /// </summary> /// <typeparam name="TResponse"></typeparam> /// <param name="method"></param> /// <param name="payload"></param> /// <returns></returns> public async Task <DaemonResponse <TResponse> > ExecuteCmdSingleAsync <TResponse>(ILogger logger, CancellationToken ct, string method, object payload = null, JsonSerializerSettings payloadJsonSerializerSettings = null) where TResponse : class { Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(method), $"{nameof(method)} must not be empty"); logger.LogInvoke(new[] { "\"" + method + "\"" }); var task = BuildRequestTask(logger, endPoints.First(), method, payload, ct, payloadJsonSerializerSettings); await Task.WhenAny(new[] { task }); var result = MapDaemonResponse <TResponse>(0, task); return(result); }
public DaemonClient(JsonSerializerSettings serializerSettings, IMessageBus messageBus, string server, string poolId) { Contract.RequiresNonNull(serializerSettings, nameof(serializerSettings)); Contract.RequiresNonNull(messageBus, nameof(messageBus)); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(poolId), $"{nameof(poolId)} must not be empty"); this.serializerSettings = serializerSettings; this.messageBus = messageBus; this.server = server; this.poolId = poolId; serializer = new JsonSerializer { ContractResolver = serializerSettings.ContractResolver }; }
/// <summary> /// Executes the request against all configured demons and returns the first successful response /// </summary> /// <typeparam name="TResponse"></typeparam> /// <returns></returns> public async Task <DaemonResponse <TResponse> > ExecuteCmdAnyAsync <TResponse>(ILogger logger, CancellationToken ct, string method, object payload = null, JsonSerializerSettings payloadJsonSerializerSettings = null, bool throwOnError = false) where TResponse : class { Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(method), $"{nameof(method)} must not be empty"); logger.LogInvoke(new[] { "\"" + method + "\"" }); var tasks = endPoints.Select(endPoint => BuildRequestTask(logger, endPoint, method, payload, ct, payloadJsonSerializerSettings)).ToArray(); var taskFirstCompleted = await Task.WhenAny(tasks); var result = MapDaemonResponse <TResponse>(0, taskFirstCompleted, throwOnError); 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"); } // 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; } } // hash it Span <byte> headerHash = stackalloc byte[32]; hashFunc(blobConverted, 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 Init(BlockTemplate blockTemplate, string jobId, PoolConfig poolConfig, BitcoinPoolConfigExtra extraPoolConfig, ClusterConfig clusterConfig, IMasterClock clock, IDestination poolAddressDestination, Network network, bool isPoS, double shareMultiplier, IHashAlgorithm coinbaseHasher, IHashAlgorithm headerHasher, IHashAlgorithm blockHasher) { Contract.RequiresNonNull(blockTemplate, nameof(blockTemplate)); Contract.RequiresNonNull(poolConfig, nameof(poolConfig)); Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig)); Contract.RequiresNonNull(clock, nameof(clock)); Contract.RequiresNonNull(poolAddressDestination, nameof(poolAddressDestination)); Contract.RequiresNonNull(coinbaseHasher, nameof(coinbaseHasher)); Contract.RequiresNonNull(headerHasher, nameof(headerHasher)); Contract.RequiresNonNull(blockHasher, nameof(blockHasher)); Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(jobId), $"{nameof(jobId)} must not be empty"); this.poolConfig = poolConfig; coin = poolConfig.Template.As <BitcoinTemplate>(); networkParams = coin.GetNetwork(network.NetworkType); txVersion = coin.CoinbaseTxVersion; this.network = network; this.clock = clock; this.poolAddressDestination = poolAddressDestination; BlockTemplate = blockTemplate; JobId = jobId; Difficulty = new Target(new NBitcoin.BouncyCastle.Math.BigInteger(BlockTemplate.Target, 16)).Difficulty; extraNoncePlaceHolderLength = BitcoinConstants.ExtranoncePlaceHolderLength; this.isPoS = isPoS; this.shareMultiplier = shareMultiplier; txComment = !string.IsNullOrEmpty(extraPoolConfig?.CoinbaseTxComment) ? extraPoolConfig.CoinbaseTxComment : coin.CoinbaseTxComment; if (coin.HasMasterNodes) { masterNodeParameters = BlockTemplate.Extra.SafeExtensionDataAs <MasterNodeBlockTemplateExtra>(); if (!string.IsNullOrEmpty(masterNodeParameters.CoinbasePayload)) { txVersion = 3; var txType = 5; txVersion = txVersion + ((uint)(txType << 16)); } } if (coin.HasPayee) { payeeParameters = BlockTemplate.Extra.SafeExtensionDataAs <PayeeBlockTemplateExtra>(); } this.coinbaseHasher = coinbaseHasher; this.headerHasher = headerHasher; this.blockHasher = blockHasher; if (!string.IsNullOrEmpty(BlockTemplate.Target)) { blockTargetValue = new uint256(BlockTemplate.Target); } else { var tmp = new Target(BlockTemplate.Bits.HexToByteArray()); blockTargetValue = tmp.ToUInt256(); } previousBlockHashReversedHex = BlockTemplate.PreviousBlockhash .HexToByteArray() .ReverseByteOrder() .ToHexString(); BuildMerkleBranches(); BuildCoinbase(); jobParams = new object[] { JobId, previousBlockHashReversedHex, coinbaseInitialHex, coinbaseFinalHex, merkleBranchesHex, BlockTemplate.Version.ToStringHex8(), BlockTemplate.Bits, BlockTemplate.CurTime.ToStringHex8(), false }; }