示例#1
0
        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);
        }
示例#3
0
        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);;
        }
示例#4
0
        protected virtual async Task<DaemonResponse<TBlockTemplate>> GetBlockTemplateAsync()
        {
            logger.LogInvoke(LogCat);

            var result = await daemon.ExecuteCmdAnyAsync<TBlockTemplate>(
                BitcoinCommands.GetBlockTemplate, getBlockTemplateParams);

            return result;
        }
示例#5
0
        private async Task <DaemonResponse <GetBlockTemplateResponse> > GetBlockTemplateAsync()
        {
            var request = new GetBlockTemplateRequest
            {
                WalletAddress = poolConfig.Address,
                ReserveSize   = MoneroConstants.ReserveSize
            };

            return(await daemon.ExecuteCmdAnyAsync <GetBlockTemplateResponse>(MC.GetBlockTemplate, request));
        }
示例#6
0
        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;
        }
示例#8
0
        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);
        }
示例#9
0
        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();
        }
示例#10
0
        private double getNetworkDifficulty()
        {
            var response = daemonClient.ExecuteCmdAnyAsync <string>(logger, AionCommands.GetDifficulty).Result;

            logger.Debug(() => $"getdifficulty: {response.Response}");
            return((double)Convert.ToInt32(response.Response, 16));
        }
示例#11
0
        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();
        }
示例#12
0
        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);
        }
示例#15
0
        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);
        }
示例#16
0
        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);
        }
示例#17
0
        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;
                }
            }
        }
示例#18
0
        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();
        }
示例#20
0
        private double getNetworkDifficulty()
        {
            var response = daemonClient.ExecuteCmdAnyAsync <string>(AionCommands.GetDifficulty).Result;

            return((double)Convert.ToInt32(response.Response, 16));
        }
示例#21
0
        protected override async Task <bool> IsDaemonConnected()
        {
            var response = await daemon.ExecuteCmdAnyAsync <string>(EC.GetPeerCount);

            return(response.Error == null && response.Response.IntegralFromHex <uint>() > 0);
        }