private async Task <DaemonResponse <TBlockTemplate> > GetBlockTemplateAsync() { var result = await daemon.ExecuteCmdAnyAsync <TBlockTemplate>( BitcoinCommands.GetBlockTemplate, getBlockTemplateParams); return(result); }
protected virtual async Task <DaemonResponse <CommerciumGetWork> > GetWorkAsync() { logger.LogInvoke(LogCat); var result = await _daemon.ExecuteCmdAnyAsync <CommerciumGetWork>(BitcoinCommands.GetWork); return(result); }
public async Task <bool> ValidateAddressAsync(string address) { Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(address), $"{nameof(address)} must not be empty"); var result = await daemon.ExecuteCmdAnyAsync <ValidateAddressResponse>(logger, AionCommands.ValidateAddress, new[] { address }); return(result.Response != null && result.Response.IsValid);; }
protected virtual async Task<DaemonResponse<TBlockTemplate>> GetBlockTemplateAsync() { logger.LogInvoke(LogCat); var result = await daemon.ExecuteCmdAnyAsync<TBlockTemplate>( BitcoinCommands.GetBlockTemplate, getBlockTemplateParams); return result; }
private async Task <DaemonResponse <GetBlockTemplateResponse> > GetBlockTemplateAsync() { var request = new GetBlockTemplateRequest { WalletAddress = poolConfig.Address, ReserveSize = MoneroConstants.ReserveSize }; return(await daemon.ExecuteCmdAnyAsync <GetBlockTemplateResponse>(MC.GetBlockTemplate, request)); }
private async Task <DaemonResponse <GetBlockTemplateResponse> > GetBlockTemplateAsync() { logger.LogInvoke(); var request = new GetBlockTemplateRequest { WalletAddress = poolConfig.Address, ReserveSize = CryptonoteConstants.ReserveSize }; return(await daemon.ExecuteCmdAnyAsync <GetBlockTemplateResponse>(logger, CryptonoteCommands.GetBlockTemplate, request)); }
private async Task<CryptonoteNetworkType> GetNetworkTypeAsync() { if (!networkType.HasValue) { var infoResponse = await daemon.ExecuteCmdAnyAsync(logger, CryptonoteCommands.GetInfo, true); var info = infoResponse.Response.ToObject<GetInfoResponse>(); networkType = info.IsTestnet ? CryptonoteNetworkType.Test : CryptonoteNetworkType.Main; } return networkType.Value; }
private async Task <MoneroNetworkType> GetNetworkTypeAsync() { if (!networkType.HasValue) { var infoResponse = await daemon.ExecuteCmdAnyAsync(MC.GetInfo); var info = infoResponse.Response.ToObject <GetInfoResponse>(); networkType = info.IsTestnet ? MoneroNetworkType.Test : MoneroNetworkType.Main; } return(networkType.Value); }
protected override async Task PostStartInitAsync() { var infoResponse = await daemon.ExecuteCmdAnyAsync(MC.GetInfo); if (infoResponse.Error != null) { logger.ThrowLogPoolStartupException($"Init RPC failed: {infoResponse.Error.Message} (Code {infoResponse.Error.Code})", LogCat); } if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) { var addressResponse = await walletDaemon.ExecuteCmdAnyAsync <GetAddressResponse>(MWC.GetAddress); // ensure pool owns wallet if (clusterConfig.PaymentProcessing?.Enabled == true && addressResponse.Response?.Address != poolConfig.Address) { logger.ThrowLogPoolStartupException($"Wallet-Daemon does not own pool-address '{poolConfig.Address}'", LogCat); } } var info = infoResponse.Response.ToObject <GetInfoResponse>(); // chain detection networkType = info.IsTestnet ? MoneroNetworkType.Test : MoneroNetworkType.Main; // address validation poolAddressBase58Prefix = LibCryptonote.DecodeAddress(poolConfig.Address); if (poolAddressBase58Prefix == 0) { logger.ThrowLogPoolStartupException("Unable to decode pool-address", LogCat); } switch (networkType) { case MoneroNetworkType.Main: if (poolAddressBase58Prefix != MoneroConstants.AddressPrefix[poolConfig.Coin.Type]) { logger.ThrowLogPoolStartupException($"Invalid pool address prefix. Expected {MoneroConstants.AddressPrefix[poolConfig.Coin.Type]}, got {poolAddressBase58Prefix}", LogCat); } break; case MoneroNetworkType.Test: if (poolAddressBase58Prefix != MoneroConstants.AddressPrefixTestnet[poolConfig.Coin.Type]) { logger.ThrowLogPoolStartupException($"Invalid pool address prefix. Expected {MoneroConstants.AddressPrefix[poolConfig.Coin.Type]}, got {poolAddressBase58Prefix}", LogCat); } break; } // if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) // ConfigureRewards(); // update stats BlockchainStats.RewardType = "POW"; BlockchainStats.NetworkType = networkType.ToString(); await UpdateNetworkStatsAsync(); SetupJobUpdates(); }
private double getNetworkDifficulty() { var response = daemonClient.ExecuteCmdAnyAsync <string>(logger, AionCommands.GetDifficulty).Result; logger.Debug(() => $"getdifficulty: {response.Response}"); return((double)Convert.ToInt32(response.Response, 16)); }
protected override async Task PostStartInitAsync() { var infoResponse = await daemon.ExecuteCmdAnyAsync(MC.GetInfo); var addressResponse = await walletDaemon.ExecuteCmdAnyAsync <GetAddressResponse>(MWC.GetAddress); if (infoResponse.Error != null) { logger.ThrowLogPoolStartupException($"Init RPC failed: {infoResponse.Error.Message} (Code {infoResponse.Error.Code})", LogCat); } // ensure pool owns wallet if (addressResponse.Response?.Address != poolConfig.Address) { logger.ThrowLogPoolStartupException($"Wallet-Daemon does not own pool-address '{poolConfig.Address}'", LogCat); } var info = infoResponse.Response.ToObject <GetInfoResponse>(); // chain detection networkType = info.IsTestnet ? MoneroNetworkType.Test : MoneroNetworkType.Main; ConfigureRewards(); // update stats BlockchainStats.RewardType = "POW"; BlockchainStats.NetworkType = networkType.ToString(); await UpdateNetworkStatsAsync(); SetupJobUpdates(); }
public async Task PayoutAsync(Balance[] balances) { Contract.RequiresNonNull(balances, nameof(balances)); // build args var amounts = balances .Where(x => x.Amount > 0) .ToDictionary(x => x.Address, x => Math.Round(x.Amount, 8)); if (amounts.Count == 0) { return; } logger.Info(() => $"[{LogCategory}] Paying out {FormatAmount(balances.Sum(x => x.Amount))} to {balances.Length} addresses"); var subtractFeesFrom = amounts.Keys.ToArray(); var args = new object[] { string.Empty, // default account amounts, // addresses and associated amounts 1, // only spend funds covered by this many confirmations "CMPool Payout", // comment subtractFeesFrom // distribute transaction fee equally over all recipients }; // send command var result = await daemon.ExecuteCmdAnyAsync <string>(BitcoinCommands.SendMany, args, new JsonSerializerSettings()); if (result.Error == null) { var txId = result.Response; // check result if (string.IsNullOrEmpty(txId)) { logger.Error(() => $"[{LogCategory}] Daemon command '{BitcoinCommands.SendMany}' did not return a transaction id!"); } else { logger.Info(() => $"[{LogCategory}] Payout transaction id: {txId}"); } PersistPayments(balances, txId); await NotifyPayoutSuccess(balances, txId, null); } else { logger.Error(() => $"[{LogCategory}] Daemon command '{BitcoinCommands.SendMany}' returned error: {result.Error.Message} code {result.Error.Code}"); await NotifyPayoutFailureAsync(balances, $"Daemon command '{BitcoinCommands.SendMany}' returned error: {result.Error.Message} code {result.Error.Code}", null); } }
private async Task <bool> SubmitBlockAsync(EthereumShare share) { // submit work var response = await daemon.ExecuteCmdAnyAsync <object>(EC.SubmitWork, new[] { share.FullNonceHex, share.HeaderHash, share.MixHash }); if (response.Error != null || (bool?)response.Response == false) { var error = response.Error?.Message ?? response?.Response?.ToString(); logger.Warn(() => $"[{LogCat}] Block {share.BlockHeight} submission failed with: {error}"); return(false); } return(true); }
private async Task <bool> SubmitBlockAsync(Share share, string fullNonceHex, string headerHash, string mixHash) { var response = await daemon.ExecuteCmdAnyAsync <object>(EC.SubmitWork, new[] { fullNonceHex, headerHash, mixHash }); if (response.Error != null || (bool?)response.Response == false) { var error = response.Error?.Message ?? response?.Response?.ToString(); logger.Warn(() => $"[{LogCat}] Block {share.BlockHeight} submission failed with: {error}"); notificationService.NotifyAdmin("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); }
private async Task PayoutBatch(Balance[] balances) { // build request var request = new TransferRequest { Destinations = balances .Where(x => x.Amount > 0) .Select(x => new TransferDestination { Address = x.Address, Amount = (ulong)Math.Floor(x.Amount * MoneroConstants.Piconero) }).ToArray(), GetTxKey = true }; if (request.Destinations.Length == 0) { return; } logger.Info(() => $"[{LogCategory}] Paying out {FormatAmount(balances.Sum(x => x.Amount))} to {balances.Length} addresses"); // send command var result = await walletDaemon.ExecuteCmdAnyAsync <TransferResponse>(MWC.Transfer, request); // gracefully handle error -4 (transaction would be too large. try /transfer_split) if (result.Error?.Code == -4) { logger.Info(() => $"[{LogCategory}] Retrying transfer using {MWC.TransferSplit}"); result = await walletDaemon.ExecuteCmdAnyAsync <TransferResponse>(MWC.TransferSplit, request); } await HandleTransferResponseAsync(result, balances); }
private async Task <EthereumBlockTemplate> GetBlockTemplateAsync() { logger.LogInvoke(LogCat); var response = await daemon.ExecuteCmdAnyAsync <JToken>(EC.GetWork); if (response.Error != null) { logger.Warn(() => $"[{LogCat}] Error(s) refreshing blocktemplate: {response.Error})"); return(null); } if (response.Response == null) { logger.Warn(() => $"[{LogCat}] Error(s) refreshing blocktemplate: {EC.GetWork} returned null response"); return(null); } // extract results var work = response.Response.ToObject <string[]>(); var result = AssembleBlockTemplate(work); return(result); }
private async Task UpdateNetworkTypeAsync() { if (!networkType.HasValue) { var infoResponse = await daemon.ExecuteCmdAnyAsync(logger, CNC.GetInfo, true); var info = infoResponse.Response.ToObject <GetInfoResponse>(); // chain detection if (!string.IsNullOrEmpty(info.NetType)) { switch (info.NetType.ToLower()) { case "mainnet": networkType = CryptonoteNetworkType.Main; break; case "stagenet": networkType = CryptonoteNetworkType.Stage; break; case "testnet": networkType = CryptonoteNetworkType.Test; break; default: logger.ThrowLogPoolStartupException($"Unsupport net type '{info.NetType}'"); break; } } else { networkType = info.IsTestnet ? CryptonoteNetworkType.Test : CryptonoteNetworkType.Main; } } }
protected override async Task PostStartInitAsync(CancellationToken ct) { var coin = poolConfig.Template.As <CryptonoteCoinTemplate>(); var infoResponse = await daemon.ExecuteCmdAnyAsync(logger, CryptonoteCommands.GetInfo); if (infoResponse.Error != null) { logger.ThrowLogPoolStartupException($"Init RPC failed: {infoResponse.Error.Message} (Code {infoResponse.Error.Code})"); } if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) { var addressResponse = await walletDaemon.ExecuteCmdAnyAsync <GetAddressResponse>(logger, ct, CryptonoteWalletCommands.GetAddress); // ensure pool owns wallet if (clusterConfig.PaymentProcessing?.Enabled == true && addressResponse.Response?.Address != poolConfig.Address) { logger.ThrowLogPoolStartupException($"Wallet-Daemon does not own pool-address '{poolConfig.Address}'"); } } var info = infoResponse.Response.ToObject <GetInfoResponse>(); // chain detection networkType = info.IsTestnet ? CryptonoteNetworkType.Test : CryptonoteNetworkType.Main; // address validation poolAddressBase58Prefix = LibCryptonote.DecodeAddress(poolConfig.Address); if (poolAddressBase58Prefix == 0) { logger.ThrowLogPoolStartupException("Unable to decode pool-address"); } switch (networkType) { case CryptonoteNetworkType.Main: if (poolAddressBase58Prefix != coin.AddressPrefix) { logger.ThrowLogPoolStartupException($"Invalid pool address prefix. Expected {coin.AddressPrefix}, got {poolAddressBase58Prefix}"); } break; case CryptonoteNetworkType.Test: if (poolAddressBase58Prefix != coin.AddressPrefixTestnet) { logger.ThrowLogPoolStartupException($"Invalid pool address prefix. Expected {coin.AddressPrefix}, got {poolAddressBase58Prefix}"); } break; } if (clusterConfig.PaymentProcessing?.Enabled == true && poolConfig.PaymentProcessing?.Enabled == true) { ConfigureRewards(); } // update stats BlockchainStats.RewardType = "POW"; BlockchainStats.NetworkType = networkType.ToString(); await UpdateNetworkStatsAsync(); // Periodically update network stats Observable.Interval(TimeSpan.FromMinutes(1)) .Select(via => Observable.FromAsync(async() => { try { await UpdateNetworkStatsAsync(); } catch (Exception ex) { logger.Error(ex); } })) .Concat() .Subscribe(); SetupJobUpdates(); }
protected override async Task PostStartInitAsync(CancellationToken ct) { var commands = new[] { new DaemonCmd(BitcoinCommands.ValidateAddress, new[] { poolConfig.Address }), new DaemonCmd(BitcoinCommands.GetInfo), new DaemonCmd(BitcoinCommands.GetDifficulty), }; var results = await _daemon.ExecuteBatchAnyAsync(commands); if (results.Any(x => x.Error != null)) { var resultList = results.ToList(); var errors = results.Where(x => x.Error != null && commands[resultList.IndexOf(x)].Method != BitcoinCommands.SubmitBlock) .ToArray(); if (errors.Any()) { logger.ThrowLogPoolStartupException($"Init RPC failed: {string.Join(", ", errors.Select(y => y.Error.Message))}", LogCat); } } // extract results var validateAddressResponse = results[0].Response.ToObject <ValidateAddressResponse>(); var daemonInfoResponse = results[1].Response.ToObject <DaemonInfo>(); var difficultyResponse = results[2].Response.ToObject <JToken>(); if (clusterConfig.PaymentProcessing?.Enabled == true) { var result = await _wallet.ExecuteCmdAnyAsync <ValidateAddressResponse>( BitcoinCommands.ValidateAddress, new[] { poolConfig.Address }); // extract results validateAddressResponse = result.Response; } // ensure pool owns wallet if (!validateAddressResponse.IsValid) { logger.ThrowLogPoolStartupException($"Daemon reports pool-address '{poolConfig.Address}' as invalid", LogCat); } if (clusterConfig.PaymentProcessing?.Enabled == true && !validateAddressResponse.IsMine) { logger.ThrowLogPoolStartupException($"Daemon does not own pool-address '{poolConfig.Address}'", LogCat); } // Create pool address script from response _poolAddressDestination = AddressToDestination(poolConfig.Address); // chain detection _networkType = daemonInfoResponse.Testnet ? BitcoinNetworkType.Test : BitcoinNetworkType.Main; // update stats BlockchainStats.NetworkType = _networkType.ToString(); BlockchainStats.RewardType = "POW"; await UpdateNetworkStatsAsync(); // Periodically update network stats Observable.Interval(TimeSpan.FromMinutes(10)) .Select(via => Observable.FromAsync(() => UpdateNetworkStatsAsync())) .Concat() .Subscribe(); SetupCrypto(); SetupJobUpdates(); }
private double getNetworkDifficulty() { var response = daemonClient.ExecuteCmdAnyAsync <string>(AionCommands.GetDifficulty).Result; return((double)Convert.ToInt32(response.Response, 16)); }
protected override async Task <bool> IsDaemonConnected() { var response = await daemon.ExecuteCmdAnyAsync <string>(EC.GetPeerCount); return(response.Error == null && response.Response.IntegralFromHex <uint>() > 0); }