Esempio n. 1
0
        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);

            switch (networkType)
            {
            case MoneroNetworkType.Main:
                if (addressPrefix != MoneroConstants.AddressPrefix[poolConfig.Coin.Type] &&
                    addressIntegratedPrefix != MoneroConstants.AddressPrefixIntegrated[poolConfig.Coin.Type])
                {
                    return(false);
                }
                break;

            case MoneroNetworkType.Test:
                if (addressPrefix != MoneroConstants.AddressPrefixTestnet[poolConfig.Coin.Type] &&
                    addressIntegratedPrefix != MoneroConstants.AddressPrefixIntegratedTestnet[poolConfig.Coin.Type])
                {
                    return(false);
                }
                break;
            }

            return(true);
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        public void Crytonote_DecodeAddress()
        {
            var address = "48nhyWcSey31ngSEhV8j8NPm6B8PistCQJBjjDjmTvRSTWYg6iocAw131vE2JPh3ps33vgQDKLrUx3fcErusYWcMJBxpm1d";
            var result  = LibCryptonote.DecodeAddress(address);

            Assert.Equal(18ul, result);
        }
Esempio n. 4
0
        public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfig)
        {
            Contract.RequiresNonNull(poolConfig, nameof(poolConfig));
            Contract.RequiresNonNull(clusterConfig, nameof(clusterConfig));

            logger             = LogUtil.GetPoolScopedLogger(typeof(JobManagerBase <MoneroJob>), poolConfig);
            this.poolConfig    = poolConfig;
            this.clusterConfig = clusterConfig;

            poolAddressBase58Prefix = LibCryptonote.DecodeAddress(poolConfig.Address);
            if (poolAddressBase58Prefix == 0)
            {
                logger.ThrowLogPoolStartupException("Unable to decode pool-address", LogCat);
            }

            // extract standard daemon endpoints
            daemonEndpoints = poolConfig.Daemons
                              .Where(x => string.IsNullOrEmpty(x.Category))
                              .ToArray();

            // extract wallet daemon endpoints
            walletDaemonEndpoints = poolConfig.Daemons
                                    .Where(x => x.Category?.ToLower() == MoneroConstants.WalletDaemonCategory)
                                    .ToArray();

            if (walletDaemonEndpoints.Length == 0)
            {
                logger.ThrowLogPoolStartupException("Wallet-RPC daemon is not configured (Daemon configuration for monero-pools require an additional entry of category \'wallet' pointing to the wallet daemon)", LogCat);
            }

            ConfigureDaemons();
        }
Esempio n. 5
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();
        }
Esempio n. 6
0
 protected override async Task RunPreInitChecksAsync()
 {
     // decode configured pool address.
     _poolAddressBase58Prefix = LibCryptonote.DecodeAddress(PoolContext.PoolAddress);
     if (_poolAddressBase58Prefix == 0)
     {
         throw new PoolStartupAbortedException("unable to decode configured pool address!");
     }
 }
Esempio n. 7
0
        private bool ValidateAddress(string address)
        {
            // check address length.
            if (address.Length != MoneroConstants.AddressLength[CoinType.XMR])
            {
                return(false);
            }

            var addressPrefix = LibCryptonote.DecodeAddress(address);

            if (addressPrefix != _poolAddressBase58Prefix)
            {
                return(false);
            }

            return(true);
        }
Esempio n. 8
0
        public bool ValidateAddress(string address)
        {
            Contract.Requires <ArgumentException>(!string.IsNullOrEmpty(address), $"{nameof(address)} must not be empty");

            if (address.Length != MoneroConstants.AddressLength)
            {
                return(false);
            }

            var addressPrefix = LibCryptonote.DecodeAddress(address);

            if (addressPrefix != poolAddressBase58Prefix)
            {
                return(false);
            }

            return(true);
        }
Esempio n. 9
0
        public override void Configure(PoolConfig poolConfig, ClusterConfig clusterConfig)
        {
            poolAddressBase58Prefix = LibCryptonote.DecodeAddress(poolConfig.Address);
            if (poolAddressBase58Prefix == 0)
            {
                logger.ThrowLogPoolStartupException("Unable to decode pool-address)", LogCat);
            }

            // extract standard daemon endpoints
            daemonEndpoints = poolConfig.Daemons
                              .Where(x => string.IsNullOrEmpty(x.Category))
                              .ToArray();

            // extract wallet daemon endpoints
            walletDaemonEndpoints = poolConfig.Daemons
                                    .Where(x => x.Category?.ToLower() == MoneroConstants.WalletDaemonCategory)
                                    .ToArray();

            base.Configure(poolConfig, clusterConfig);
        }
Esempio n. 10
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();
        }
Esempio n. 11
0
 public void Cryptonote_DecodeAddress_Should_Throw_On_Null_Or_Empty_Argument()
 {
     Assert.Throws <ArgumentException>(() => LibCryptonote.DecodeAddress(null));
     Assert.Throws <ArgumentException>(() => LibCryptonote.DecodeAddress(""));
 }
Esempio n. 12
0
        public async Task PayoutAsync(Balance[] balances)
        {
            Contract.RequiresNonNull(balances, nameof(balances));

            // ensure we have peers
            var infoResponse = await daemon.ExecuteCmdAnyAsync <GetInfoResponse>(MC.GetInfo);

            if (infoResponse.Error != null || infoResponse.Response == null ||
                infoResponse.Response.IncomingConnectionsCount + infoResponse.Response.OutgoingConnectionsCount < 3)
            {
#if !DEBUG
                logger.Warn(() => $"[{LogCategory}] Payout aborted. Not enough peers (4 required)");
                return;
#endif
            }

            // validate addresses
            balances = balances
                       .Where(x =>
            {
                ExtractAddressAndPaymentId(x.Address, out var address, out var paymentId);

                var addressPrefix           = LibCryptonote.DecodeAddress(address);
                var addressIntegratedPrefix = LibCryptonote.DecodeIntegratedAddress(address);

                switch (networkType)
                {
                case MoneroNetworkType.Main:
                    if (addressPrefix != MoneroConstants.AddressPrefix[poolConfig.Coin.Type] &&
                        addressIntegratedPrefix != MoneroConstants.AddressPrefixIntegrated[poolConfig.Coin.Type])
                    {
                        logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address {x.Address}");
                        return(false);
                    }
                    break;

                case MoneroNetworkType.Test:
                    if (addressPrefix != MoneroConstants.AddressPrefixTestnet[poolConfig.Coin.Type] &&
                        addressIntegratedPrefix != MoneroConstants.AddressPrefixIntegratedTestnet[poolConfig.Coin.Type])
                    {
                        logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address {x.Address}");
                        return(false);
                    }
                    break;
                }

                return(true);
            })
                       .ToArray();

            // simple balances first
            var simpleBalances = balances
                                 .Where(x =>
            {
                ExtractAddressAndPaymentId(x.Address, out var address, out var paymentId);

                var hasPaymentId            = paymentId != null;
                var isIntegratedAddress     = false;
                var addressIntegratedPrefix = LibCryptonote.DecodeIntegratedAddress(address);

                switch (networkType)
                {
                case MoneroNetworkType.Main:
                    if (addressIntegratedPrefix == MoneroConstants.AddressPrefixIntegrated[poolConfig.Coin.Type])
                    {
                        isIntegratedAddress = true;
                    }
                    break;

                case MoneroNetworkType.Test:
                    if (addressIntegratedPrefix == MoneroConstants.AddressPrefixIntegratedTestnet[poolConfig.Coin.Type])
                    {
                        isIntegratedAddress = true;
                    }
                    break;
                }

                return(!hasPaymentId && !isIntegratedAddress);
            })
                                 .ToArray();

            if (simpleBalances.Length > 0)
            {
                await PayoutBatch(simpleBalances);
            }

            // balances with paymentIds
            var minimumPaymentToPaymentId = extraConfig?.MinimumPaymentToPaymentId ?? poolConfig.PaymentProcessing.MinimumPayment;

            var paymentIdBalances = balances.Except(simpleBalances)
                                    .Where(x => x.Amount >= minimumPaymentToPaymentId)
                                    .ToArray();

            foreach (var balance in paymentIdBalances)
            {
                await PayoutToPaymentId(balance);
            }
        }
Esempio n. 13
0
        public async Task PayoutAsync(Balance[] balances)
        {
            Contract.RequiresNonNull(balances, nameof(balances));

            var coin = poolConfig.Template.As <CryptonoteCoinTemplate>();

#if !DEBUG // ensure we have peers
            var infoResponse = await daemon.ExecuteCmdAnyAsync <GetInfoResponse>(logger, CNC.GetInfo);

            if (infoResponse.Error != null || infoResponse.Response == null ||
                infoResponse.Response.IncomingConnectionsCount + infoResponse.Response.OutgoingConnectionsCount < 3)
            {
                logger.Warn(() => $"[{LogCategory}] Payout aborted. Not enough peers (4 required)");
                return;
            }
#endif
            // validate addresses
            balances = balances
                       .Where(x =>
            {
                ExtractAddressAndPaymentId(x.Address, out var address, out var paymentId);

                var addressPrefix           = LibCryptonote.DecodeAddress(address);
                var addressIntegratedPrefix = LibCryptonote.DecodeIntegratedAddress(address);

                switch (networkType)
                {
                case CryptonoteNetworkType.Main:
                    if (addressPrefix != coin.AddressPrefix &&
                        addressIntegratedPrefix != coin.AddressPrefixIntegrated)
                    {
                        logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address {x.Address}");
                        return(false);
                    }

                    break;

                case CryptonoteNetworkType.Test:
                    if (addressPrefix != coin.AddressPrefixTestnet &&
                        addressIntegratedPrefix != coin.AddressPrefixIntegratedTestnet)
                    {
                        logger.Warn(() => $"[{LogCategory}] Excluding payment to invalid address {x.Address}");
                        return(false);
                    }

                    break;
                }

                return(true);
            })
                       .ToArray();

            // simple balances first
            var simpleBalances = balances
                                 .Where(x =>
            {
                ExtractAddressAndPaymentId(x.Address, out var address, out var paymentId);

                var hasPaymentId            = paymentId != null;
                var isIntegratedAddress     = false;
                var addressIntegratedPrefix = LibCryptonote.DecodeIntegratedAddress(address);

                switch (networkType)
                {
                case CryptonoteNetworkType.Main:
                    if (addressIntegratedPrefix == coin.AddressPrefixIntegrated)
                    {
                        isIntegratedAddress = true;
                    }
                    break;

                case CryptonoteNetworkType.Test:
                    if (addressIntegratedPrefix == coin.AddressPrefixIntegratedTestnet)
                    {
                        isIntegratedAddress = true;
                    }
                    break;
                }

                return(!hasPaymentId && !isIntegratedAddress);
            })
                                 .OrderByDescending(x => x.Amount)
                                 .ToArray();

            if (simpleBalances.Length > 0)
#if false
            { await PayoutBatch(simpleBalances); }
#else
            {
                var maxBatchSize = 15;  // going over 15 yields "sv/gamma are too large"
                var pageSize     = maxBatchSize;
                var pageCount    = (int)Math.Ceiling((double)simpleBalances.Length / pageSize);

                for (var i = 0; i < pageCount; i++)
                {
                    var page = simpleBalances
                               .Skip(i * pageSize)
                               .Take(pageSize)
                               .ToArray();

                    if (!await PayoutBatch(page))
                    {
                        break;
                    }
                }
            }
#endif
            // balances with paymentIds
            var minimumPaymentToPaymentId = extraConfig?.MinimumPaymentToPaymentId ?? poolConfig.PaymentProcessing.MinimumPayment;

            var paymentIdBalances = balances.Except(simpleBalances)
                                    .Where(x => x.Amount >= minimumPaymentToPaymentId)
                                    .ToArray();

            foreach (var balance in paymentIdBalances)
            {
                if (!await PayoutToPaymentId(balance))
                {
                    break;
                }
            }

            // save wallet
            await walletDaemon.ExecuteCmdSingleAsync <JToken>(logger, CryptonoteWalletCommands.Store);
        }
Esempio n. 14
0
        public void Cryptonote_DecodeAddress_Should_Match()
        {
            var result = LibCryptonote.DecodeAddress("9wviCeWe2D8XS82k2ovp5EUYLzBt9pYNW2LXUFsZiv8S3Mt21FZ5qQaAroko1enzw3eGr9qC7X1D7Geoo2RrAotYPwq9Gm8");

            Assert.Equal(53u, result);
        }