コード例 #1
0
        private void OnShare(object sender, EventArgs e)
        {
            var shareArgs = (ShareEventArgs)e;
            var miner     = shareArgs.Miner;

            if (miner == null)
            {
                return;
            }

            var now = TimeHelpers.NowInUnixTimestamp();

            if (miner.VardiffBuffer == null)
            {
                miner.LastVardiffRetarget  = now - Config.RetargetTime / 2;
                miner.LastVardiffTimestamp = now;
                miner.VardiffBuffer        = new RingBuffer(_bufferSize);
                return;
            }

            var sinceLast = now - miner.LastVardiffTimestamp; // how many seconds elapsed since last share?

            miner.VardiffBuffer.Append(sinceLast);            // append it to vardiff buffer.
            miner.LastVardiffTimestamp = now;

            if (now - miner.LastVardiffRetarget < Config.RetargetTime && miner.VardiffBuffer.Size > 0) // check if we need a re-target.
            {
                return;
            }

            miner.LastVardiffRetarget = now;
            var average   = miner.VardiffBuffer.Average;
            var deltaDiff = Config.TargetTime / average;

            if (average > _tMax && miner.Difficulty > Config.MinimumDifficulty)
            {
                if (deltaDiff * miner.Difficulty < Config.MinimumDifficulty)
                {
                    deltaDiff = Config.MinimumDifficulty / miner.Difficulty;
                }
            }
            else if (average < _tMin)
            {
                if (deltaDiff * miner.Difficulty > Config.MaximumDifficulty)
                {
                    deltaDiff = Config.MaximumDifficulty / miner.Difficulty;
                }
            }
            else
            {
                return;
            }

            var newDifficulty = miner.Difficulty * deltaDiff; // calculate the new difficulty.

            miner.SetDifficulty(newDifficulty);               // set the new difficulty and send it.
            _logger.Debug("Difficulty updated to {0} for miner: {1:l}", miner.Difficulty, miner.Username);

            miner.VardiffBuffer.Clear();
        }
コード例 #2
0
        public void AddShare(IShare share)
        {
            try
            {
                if (!IsEnabled || !_redisProvider.IsConnected)
                {
                    return;
                }

                //_client.StartPipe(); // batch the commands.

                // add the share to round
                var currentKey = string.Format("{0}:shares:round:current", _coin);
                _redisProvider.Client.HIncrByFloat(currentKey, share.Miner.Username, share.Difficulty);

                // increment shares stats.
                var statsKey = string.Format("{0}:stats", _coin);
                _redisProvider.Client.HIncrBy(statsKey, share.IsValid ? "validShares" : "invalidShares", 1);

                // add to hashrate
                if (share.IsValid)
                {
                    var hashrateKey = string.Format("{0}:hashrate", _coin);
                    var entry       = string.Format("{0}:{1}", share.Difficulty, share.Miner.Username);
                    _redisProvider.Client.ZAdd(hashrateKey, Tuple.Create(TimeHelpers.NowInUnixTimestamp(), entry));
                }

                //_client.EndPipe(); // execute the batch commands.
            }
            catch (Exception e)
            {
                _logger.Error("An exception occured while comitting share: {0:l}", e.Message);
            }
        }
コード例 #3
0
        /// <summary>
        /// Creates a new instance of generation transaction.
        /// </summary>
        /// <param name="extraNonce">The extra nonce.</param>
        /// <param name="daemonClient">The daemon client.</param>
        /// <param name="blockTemplate">The block template.</param>
        /// <param name="poolConfig">The associated pool's configuration</param>
        /// <remarks>
        /// Reference implementations:
        /// https://github.com/zone117x/node-stratum-pool/blob/b24151729d77e0439e092fe3a1cdbba71ca5d12e/lib/transactions.js
        /// https://github.com/Crypto-Expert/stratum-mining/blob/master/lib/coinbasetx.py
        /// </remarks>
        public GenerationTransaction(IExtraNonce extraNonce, IDaemonClient daemonClient, IBlockTemplate blockTemplate, IPoolConfig poolConfig)
        {
            // TODO: we need a whole refactoring here.
            // we should use DI and it shouldn't really require daemonClient connection to function.

            BlockTemplate = blockTemplate;
            ExtraNonce    = extraNonce;
            PoolConfig    = poolConfig;

            Version   = 1;//change version for bitcoin like
            TxMessage = Serializers.SerializeString(poolConfig.Meta.TxMessage);
            LockTime  = 0;



            // transaction inputs
            Inputs = new List <TxIn>
            {
                new TxIn
                {
                    PreviousOutput = new OutPoint
                    {
                        Hash  = Hash.ZeroHash,
                        Index = (UInt32)Math.Pow(2, 32) - 1
                    },
                    Sequence        = (UInt32)Math.Pow(2, 32) - 1,
                    SignatureScript =
                        new SignatureScript(
                            blockTemplate.Height,
                            //blockTemplate.CoinBaseAux.Flags,
                            "",
                            TimeHelpers.NowInUnixTimestamp(),
                            (byte)extraNonce.ExtraNoncePlaceholder.Length,
                            "")
                }
            };

            // transaction outputs
            Outputs = new Outputs(daemonClient, poolConfig.Coin);


            double blockReward = BlockTemplate.Coinbasevalue; // the amount rewarded by the block.



            // generate output transactions for recipients (set in config).

            /*foreach (var pair in poolConfig.Rewards)
             * {
             *  var amount = blockReward * pair.Value / 100; // calculate the amount he recieves based on the percent of his shares.
             *  blockReward -= amount;
             *
             *  Outputs.AddRecipient(pair.Key, amount);
             * }*/

            // send the remaining coins to pool's central wallet.
            Outputs.AddPoolWallet(poolConfig.Wallet.Adress, blockReward);
        }
コード例 #4
0
        /// <summary>
        /// Creates a new instance of generation transaction.
        /// </summary>
        /// <param name="extraNonce">The extra nonce.</param>
        /// <param name="daemonClient">The daemon client.</param>
        /// <param name="blockTemplate">The block template.</param>
        /// <param name="poolConfig">The associated pool's configuration</param>
        /// <remarks>
        /// Reference implementations:
        /// https://github.com/zone117x/node-stratum-pool/blob/b24151729d77e0439e092fe3a1cdbba71ca5d12e/lib/transactions.js
        /// https://github.com/Crypto-Expert/stratum-mining/blob/master/lib/coinbasetx.py
        /// </remarks>
        public GenerationTransaction(IExtraNonce extraNonce, IDaemonClient daemonClient,
                                     IBlockTemplate blockTemplate, IPoolConfig poolConfig)
        {
            // TODO: we need a whole refactoring here.
            // we should use DI and it shouldn't really require daemonClient connection to function.

            BlockTemplate = blockTemplate;
            ExtraNonce    = extraNonce;
            PoolConfig    = poolConfig;

            Version   = blockTemplate.Version;
            TxMessage = Serializers.SerializeString(poolConfig.Meta.TxMessage);
            LockTime  = 0;

            // transaction inputs
            Inputs = new List <TxIn>
            {
                new TxIn
                {
                    PreviousOutput = new OutPoint
                    {
                        Hash  = Hash.ZeroHash,
                        Index = (UInt32)Math.Pow(2, 32) - 1
                    },
                    Sequence        = 0x0,
                    SignatureScript =
                        new SignatureScript(
                            blockTemplate.Height,
                            blockTemplate.CoinBaseAux.Flags,
                            TimeHelpers.NowInUnixTimestamp(),
                            (byte)extraNonce.ExtraNoncePlaceholder.Length,
                            "/CoiniumServ/")
                }
            };

            // transaction outputs
            Outputs = new Outputs(daemonClient, poolConfig.Coin);
            double blockReward = BlockTemplate.Coinbasevalue; // the amount rewarded by the block.

            // generate output transactions for recipients (set in config).
            foreach (var pair in poolConfig.Rewards)
            {
                var amount = blockReward * pair.Value / 100; // calculate the amount the recieves based on the percent of his shares.
                blockReward -= amount;
                Outputs.AddRecipient(pair.Key, amount);
            }

            // send the remaining coins to pool's central wallet.
            Outputs.AddPoolWallet(poolConfig.Wallet.Adress, blockReward);

            // Final output is witness
            //https://github.com/slush0/stratum-mining/pull/16/files?diff=unified
            if (!string.IsNullOrEmpty(BlockTemplate.Default_witness_commitment))
            {
                Outputs.AddWitnessOutput(BlockTemplate.Default_witness_commitment.HexToByteArray());
            }
        }
コード例 #5
0
ファイル: ScryptN.cs プロジェクト: meritlabs/merit-pool
        public byte[] Hash(byte[] input)
        {
            var now = (UInt64)TimeHelpers.NowInUnixTimestamp();

            var index   = _timeTable.OrderBy(x => x.Key).First(x => x.Value < now).Key;
            var nFactor = (int)(Math.Log(index) / Math.Log(2));
            var n       = 1 << nFactor;

            return(SCrypt.ComputeDerivedKey(input, input, n, _r, _p, null, 32));
        }
コード例 #6
0
ファイル: Pool.cs プロジェクト: tross2015/CoiniumServ
        private void CalculateHashrate()
        {
            // read hashrate stats.
            var windowTime = TimeHelpers.NowInUnixTimestamp() - _configManager.StatisticsConfig.HashrateWindow;

            _storage.DeleteExpiredHashrateData(windowTime);
            var hashrates = _storage.GetHashrateData(windowTime);

            double total = hashrates.Sum(pair => pair.Value);

            Hashrate = Convert.ToUInt64(_shareMultiplier * total / _configManager.StatisticsConfig.HashrateWindow);
        }
コード例 #7
0
ファイル: BanManager.cs プロジェクト: turbobit/merit-pool
        private bool BanExpired(IPAddress ip)
        {
            var banTime = _bannedIps[ip];

            var elapsedTime = TimeHelpers.NowInUnixTimestamp() - banTime; // elapsed time since his ban.
            var timeLeft    = Config.Duration - elapsedTime;              // time left for his ban

            if (timeLeft > 0)                                             // if he has still remaining time
            {
                return(false);
            }

            return(true);
        }
コード例 #8
0
ファイル: Pool.cs プロジェクト: turbobit/merit-pool
        private void CalculateHashrate()
        {
            // read hashrate stats.
            var windowTime = TimeHelpers.NowInUnixTimestamp() - _configManager.StatisticsConfig.HashrateWindow;

            _storage.DeleteExpiredHashrateData(windowTime);
            var hashrates = _storage.GetHashrateData(windowTime);

            double total = hashrates.Sum(pair => pair.Value);

            Hashrate = _shareMultiplier * total / _configManager.StatisticsConfig.HashrateWindow;

            // TODO: fix pool hashrate calculation
            _logger.Debug("Pool hashrate window: {0} total: {1} hashrate: {2:0.000000000}", _configManager.StatisticsConfig.HashrateWindow, total, Hashrate);
        }
コード例 #9
0
ファイル: BanManager.cs プロジェクト: turbobit/merit-pool
        private void Ban(IMiner miner)
        {
            // TODO: add vanilla miners to banlist too.
            if (miner is IGetworkMiner) // as vanilla miners doesn't use persistent connections, we don't need to disconect him
            {
                return;                 // but just blacklist his ip.
            }
            var client = (IClient)miner;
            var ip     = client.Connection.RemoteEndPoint.Address;

            if (!_bannedIps.ContainsKey(ip))
            {
                _bannedIps.Add(ip, TimeHelpers.NowInUnixTimestamp());
            }

            client.Connection.Disconnect();
        }
コード例 #10
0
ファイル: Job.cs プロジェクト: meritlabs/merit-pool
        /// <summary>
        /// Creates a new instance of JobNotification.
        /// </summary>
        /// <param name="id"></param>
        /// <param name="algorithm"></param>
        /// <param name="blockTemplate"></param>
        /// <param name="generationTransaction"></param>
        public Job(UInt64 id, IHashAlgorithm algorithm, IBlockTemplate blockTemplate, IGenerationTransaction generationTransaction)
        {
            // init the values.
            Id                        = id;
            HashAlgorithm             = algorithm;
            BlockTemplate             = blockTemplate;
            Height                    = blockTemplate.Height;
            GenerationTransaction     = generationTransaction;
            PreviousBlockHash         = blockTemplate.PreviousBlockHash.HexToByteArray().ToHexString();
            PreviousBlockHashReversed = blockTemplate.PreviousBlockHash.HexToByteArray().ReverseByteOrder().ToHexString();
            CoinbaseInitial           = generationTransaction.Initial.ToHexString();
            CoinbaseFinal             = generationTransaction.Final.ToHexString();
            CreationTime              = TimeHelpers.NowInUnixTimestamp();
            EdgeBits                  = blockTemplate.EdgeBits;

            _shares = new List <UInt64>();

            // calculate the merkle tree
            var hashes = BlockTemplate.Transactions.Slice(1, BlockTemplate.Transactions.Length).GetHashList();

            hashes.AddRange(BlockTemplate.Invites.GetHashList());
            hashes.AddRange(BlockTemplate.Referrals.GetHashList());

            MerkleTree = new MerkleTree(hashes);

            // set version
            Version = BitConverter.GetBytes(blockTemplate.Version.BigEndian()).ToHexString();

            // set the encoded difficulty (bits)
            EncodedDifficulty = blockTemplate.Bits;

            // set the target
            Target = string.IsNullOrEmpty(blockTemplate.Target)
                ? EncodedDifficulty.BigIntFromBitsHex()
                : BigInteger.Parse(blockTemplate.Target, NumberStyles.HexNumber);

            // set the block diff
            Difficulty = ((double)new BigRational(AlgorithmManager.Diff1, Target));

            // set the ntime
            NTime = BitConverter.GetBytes(blockTemplate.CurTime.BigEndian()).ToHexString();
        }
コード例 #11
0
        private void CleanUp(object state)
        {
            var startingCount = _jobs.Count;

            // calculate the cleanup delta time - jobs created before this will be cleaned up.
            var delta = TimeHelpers.NowInUnixTimestamp() - _cleanupFrequency;

            // find expired jobs that were created before our calcualted delta time.
            _jobs = _jobs.Where(j => j.Value.CreationTime >= delta || j.Value == Current)
                    .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

            var cleanedCount = startingCount - _jobs.Count;

            if (cleanedCount > 0)
            {
                _logger.Debug("Cleaned-up {0} expired jobs", cleanedCount);
            }

            _cleanupTimer.Change(_cleanupFrequency * 1000, Timeout.Infinite); // reset the cleanup timer.
        }
コード例 #12
0
        /// <summary>
        /// Creates a new instance of generation transaction.
        /// </summary>
        /// <param name="extraNonce">The extra nonce.</param>
        /// <param name="blockTemplate">The block template.</param>
        /// <param name="poolConfig">The associated pool's configuration</param>
        /// <remarks>
        /// Reference implementations:
        /// https://github.com/zone117x/node-stratum-pool/blob/b24151729d77e0439e092fe3a1cdbba71ca5d12e/lib/transactions.js
        /// https://github.com/Crypto-Expert/stratum-mining/blob/master/lib/coinbasetx.py
        /// </remarks>
        public GenerationTransaction(IExtraNonce extraNonce, IBlockTemplate blockTemplate, IPoolConfig poolConfig)
        {
            _logger = Log.ForContext <GenerationTransaction>();

            BlockTemplate = blockTemplate;
            ExtraNonce    = extraNonce;
            PoolConfig    = poolConfig;

            Version   = blockTemplate.Version;
            TxMessage = Serializers.SerializeString(poolConfig.Meta.TxMessage);
            LockTime  = 0;

            CoinbaseSignatureScript =
                new SignatureScript(
                    blockTemplate.Height,
                    blockTemplate.CoinBaseAux.Flags,
                    TimeHelpers.NowInUnixTimestamp(),
                    (byte)extraNonce.ExtraNoncePlaceholder.Length,
                    "/MeritPool/");
        }
コード例 #13
0
        public void AddShare(IShare share)
        {
            try
            {
                if (!IsEnabled || !_redisProvider.IsConnected)
                {
                    return;
                }

                //_client.StartPipe(); // batch the commands.

                // add the share to round
                var currentKey = string.Format("{0}:shares:round:current", _coin);
                var miner      = (IStratumMiner)share.Miner;
                _redisProvider.Client.HIncrByFloat(currentKey, miner.Username, (double)miner.Difficulty);

                // increment shares stats.
                var statsKey = string.Format("{0}:stats", _coin);
                _redisProvider.Client.HIncrBy(statsKey, share.IsValid ? "validShares" : "invalidShares", 1);

                // add to hashrate
                if (share.IsValid)
                {
                    var    hashrateKey      = string.Format("{0}:hashrate", _coin);
                    var    randomModifier   = Convert.ToString(miner.ValidShareCount, 16).PadLeft(8, '0');
                    string modifiedUsername = miner.Username + randomModifier;
                    var    entry            = string.Format("{0}:{1}", (double)miner.Difficulty, modifiedUsername);
                    _redisProvider.Client.ZAdd(hashrateKey, Tuple.Create((double)TimeHelpers.NowInUnixTimestamp(), entry));
                }

                //_client.EndPipe(); // execute the batch commands.
            }
            catch (Exception e)
            {
                _logger.Error("An exception occured while comitting share: {0:l}\n{1:l}", e.Message, e.StackTrace);
                //Bug 2017-07-17 16:00
                //An exception occured while comitting share:
                //"Cannot write to a BufferedStream while the read buffer is not empty if the underlying stream is not seekable.
                //Ensure that the stream underlying this BufferedStream can seek or avoid interleaving read and write operations on this BufferedStream."
            }
        }
コード例 #14
0
        public void AddShare(IShare share)
        {
            try
            {
                if (!IsEnabled || !_redisProvider.IsConnected)
                {
                    return;
                }

                //_client.StartPipe(); // batch the commands.

                // add the share to round
                var currentKey = $"{_coin}:shares:round:current";
                var miner      = (IStratumMiner)share.Miner;
                _redisProvider.Client.HIncrByFloat(currentKey, miner.Username, (double)share.Difficulty);
                //_redisProvider.Client.HIncrByFloat(currentKey, share.Miner.Username, share.Difficulty);

                // increment shares stats.
                var statsKey = $"{_coin}:stats";
                _redisProvider.Client.HIncrBy(statsKey, share.IsValid ? "validShares" : "invalidShares", 1);

                // add to hashrate
                if (share.IsValid)
                {
                    var    hashrateKey      = $"{_coin}:hashrate";
                    var    randomModifier   = Convert.ToString(miner.ValidShareCount, 16).PadLeft(8, '0');
                    string modifiedUsername = miner.Username + randomModifier;
                    //var entry = $"{share.Difficulty}:{share.Miner.Username}";
                    var entry = string.Format("{0}:{1}", (double)miner.Difficulty, modifiedUsername);
                    _redisProvider.Client.ZAdd(hashrateKey, Tuple.Create((double)TimeHelpers.NowInUnixTimestamp(), entry));
                }

                //_client.EndPipe(); // execute the batch commands.
            }
            catch (Exception e)
            {
                _logger.Error("An exception occurred while committing share: {0:l}", e.Message);
            }
        }
コード例 #15
0
ファイル: Share.cs プロジェクト: zz0412/ZCoiniumServ
        public Share(IStratumMiner miner, UInt64 jobId, IJob job, string extraNonce2, string nTimeString, string nSolution)
        {
            Miner = miner;
            JobId = jobId;
            Job   = job;
            Error = ShareError.None;

            var submitTime = TimeHelpers.NowInUnixTimestamp(); // time we recieved the share from miner.

            if (Job == null)
            {
                Error = ShareError.JobNotFound;
                return;
            }

            // check size of miner supplied extraNonce2
            if (extraNonce2.Length / 2 != ExtraNonce.ExpectedExtraNonce2Size)
            {
                Error = ShareError.IncorrectExtraNonce2Size;
                return;
            }
            ExtraNonce2 = extraNonce2; // set extraNonce2 for the share.

            // check size of miner supplied nTime.
            if (nTimeString.Length != 8)
            {
                Error = ShareError.IncorrectNTimeSize;
                return;
            }
            NTime = Convert.ToUInt32(nTimeString.HexToByteArray().ReverseBuffer().ToHexString(), 16); // read ntime for the share

            // make sure NTime is within range.
            if (NTime < job.BlockTemplate.CurTime || NTime > submitTime + 7200)
            {
                Error = ShareError.NTimeOutOfRange;
                return;
            }

            // set job supplied parameters.
            Height      = job.BlockTemplate.Height; // associated job's block height.
            ExtraNonce1 = miner.ExtraNonce;         // extra nonce1 assigned to miner.

            // check for duplicate shares.
            if (!Job.RegisterShare(this)) // try to register share with the job and see if it's duplicated or not.
            {
                Error = ShareError.DuplicateShare;
                return;
            }

            // construct the coinbase.
            CoinbaseBuffer = Serializers.SerializeCoinbase(Job, ExtraNonce1);
            CoinbaseHash   = Coin.Coinbase.Utils.HashCoinbase(CoinbaseBuffer);

            string nonceString = extraNonce2.HexToByteArray().ReverseBuffer().ToHexString() + ExtraNonce1.BigEndian().ToString("x8");

            byte[] nonce = nonceString.HexToByteArray();


            // create the merkle root.
            MerkleRoot = Job.MerkleTree.WithFirst(CoinbaseHash).ReverseBuffer();

            // create the block headers
            {
                HeaderBuffer = Serializers.SerializeHeader(Job, MerkleRoot, nonce, NTime,
                                                           nSolution.HexToByteArray().ReverseBuffer());
                HeaderHash = Job.HashAlgorithm.Hash(HeaderBuffer);
            }

            HeaderValue = new BigInteger(HeaderHash);

            // calculate the share difficulty
            Difficulty = ((double)new BigRational(AlgorithmManager.Diff1, HeaderValue)) * Job.HashAlgorithm.Multiplier;

            // calculate the block difficulty
            BlockDiffAdjusted = Job.Difficulty * Job.HashAlgorithm.Multiplier;

            // check if block candicate
            if (Job.Target >= HeaderValue)
            {
                IsBlockCandidate = true;
                BlockHex         = Serializers.SerializeBlock(Job, HeaderBuffer, CoinbaseBuffer, miner.Pool.Config.Coin.Options.IsProofOfStakeHybrid);
                BlockHash        = HeaderBuffer.DoubleDigest().ReverseBuffer();
            }
            else
            {
                IsBlockCandidate = false;
                BlockHash        = HeaderBuffer.DoubleDigest().ReverseBuffer();

                // Check if share difficulty reaches miner difficulty.
                var lowDifficulty = Difficulty / miner.Difficulty < 0.99; // share difficulty should be equal or more then miner's target difficulty.

                if (!lowDifficulty)                                       // if share difficulty is high enough to match miner's current difficulty.
                {
                    return;                                               // just accept the share.
                }
                if (Difficulty >= miner.PreviousDifficulty)               // if the difficulty matches miner's previous difficulty before the last vardiff triggered difficulty change
                {
                    return;                                               // still accept the share.
                }
                // if the share difficulty can't match miner's current difficulty or previous difficulty
                Error = ShareError.LowDifficultyShare; // then just reject the share with low difficult share error.
            }
        }
コード例 #16
0
        public Share(IStratumMiner miner, UInt64 jobId, IJob job, string extraNonce2, string nTimeString, string nonceString, UInt32[] cycle)
        {
            Miner = miner;
            JobId = jobId;
            Job   = job;
            Error = ShareError.None;
            Cycle = cycle;

            var submitTime = TimeHelpers.NowInUnixTimestamp(); // time we recieved the share from miner.

            if (Job == null)
            {
                Error = ShareError.JobNotFound;
                return;
            }

            // check size of miner supplied extraNonce2
            if (extraNonce2.Length / 2 != ExtraNonce.ExpectedExtraNonce2Size)
            {
                Error = ShareError.IncorrectExtraNonce2Size;
                return;
            }
            ExtraNonce2 = Convert.ToUInt32(extraNonce2, 16); // set extraNonce2 for the share.

            // check size of miner supplied nTime.
            if (nTimeString.Length != 8)
            {
                Error = ShareError.IncorrectNTimeSize;
                return;
            }
            NTime = Convert.ToUInt32(nTimeString, 16); // read ntime for the share

            // make sure NTime is within range.
            if (NTime < job.BlockTemplate.CurTime || NTime > submitTime + 7200)
            {
                Error = ShareError.NTimeOutOfRange;
                return;
            }

            // check size of miner supplied nonce.
            if (nonceString.Length != 8)
            {
                Error = ShareError.IncorrectNonceSize;
                return;
            }
            Nonce = Convert.ToUInt32(nonceString, 16); // nonce supplied by the miner for the share.

            // set job supplied parameters.
            Height      = job.BlockTemplate.Height; // associated job's block height.
            ExtraNonce1 = miner.ExtraNonce;         // extra nonce1 assigned to miner.

            // check for duplicate shares.
            if (!Job.RegisterShare(this)) // try to register share with the job and see if it's duplicated or not.
            {
                Error = ShareError.DuplicateShare;
                return;
            }

            // construct the coinbase.
            CoinbaseBuffer = Serializers.SerializeCoinbase(Job, ExtraNonce1, ExtraNonce2);
            CoinbaseHash   = Coin.Coinbase.Utils.HashCoinbase(CoinbaseBuffer);

            // create the merkle root.
            MerkleRoot = Job.MerkleTree.WithFirst(CoinbaseHash).ReverseBuffer();

            // create the block headers
            HeaderBuffer = Serializers.SerializeHeader(Job, MerkleRoot, NTime, Nonce);
            HeaderHash   = Job.HashAlgorithm.Hash(HeaderBuffer);
            HeaderValue  = new BigInteger(HeaderHash);
            BlockHash    = HeaderBuffer.DoubleDigest().ReverseBuffer();

            if (!checkCycle())
            {
                Error = ShareError.IncorrectCycle;
                return;
            }

            var _logger = Log.ForContext <Share>();

            using (var stream = new MemoryStream())
            {
                stream.WriteByte((byte)Cycle.Length);
                foreach (var edge in Cycle)
                {
                    stream.WriteValueU32(edge);
                }

                CycleBuffer = stream.ToArray();
            }

            CycleHash  = Job.HashAlgorithm.Hash(CycleBuffer);
            CycleValue = new BigInteger(CycleHash);

            // calculate the share difficulty
            Difficulty = ((double)new BigRational(AlgorithmManager.Diff1, CycleValue)) * Job.HashAlgorithm.Multiplier;

            // calculate the block difficulty
            BlockDiffAdjusted = Job.Difficulty * Job.HashAlgorithm.Multiplier;

            // check if block candicate
            if (Job.Target >= CycleValue)
            {
                if (Difficulty < 0)
                {
                    IsBlockCandidate = false;
                    if (miner.Software == MinerSoftware.MeritMiner && miner.SoftwareVersion == new Version("0.1.0"))
                    {
                        // if we use merit-miner 0.1.0 diff can be negative
                        Error = ShareError.NegativeDifficultyShareOutdatedMiner;
                    }
                    else
                    {
                        Error = ShareError.NegativeDifficultyShare;
                    }
                    return;
                }
                IsBlockCandidate = true;

                BlockHex = Serializers.SerializeBlock(Job, HeaderBuffer, CoinbaseBuffer, CycleBuffer, miner.Pool.Config.Coin.Options.IsProofOfStakeHybrid);
            }
            else
            {
                IsBlockCandidate = false;

                // Check if share difficulty reaches miner difficulty.
                var lowDifficulty = Difficulty / miner.Difficulty < 0.99; // share difficulty should be equal or more then miner's target difficulty.

                if (!lowDifficulty)                                       // if share difficulty is high enough to match miner's current difficulty.
                {
                    return;                                               // just accept the share.
                }

                if (miner.PreviousDifficulty > 0 && Difficulty >= miner.PreviousDifficulty)  // if the difficulty matches miner's previous difficulty before the last vardiff triggered difficulty change
                {
                    _logger.Debug("\tprevdiff lower; diff >= prevdiff: {0}::{1}", Difficulty, miner.PreviousDifficulty);
                    return; // still accept the share.
                }


                // if the share difficulty can't match miner's current difficulty or previous difficulty
                Error = ShareError.LowDifficultyShare; // then just reject the share with low difficult share error.
            }
        }
コード例 #17
0
ファイル: Share.cs プロジェクト: tross2015/CoiniumServ
        public Share(IStratumMiner miner, UInt64 jobId, IJob job, string extraNonce2, string nTimeString,
                     string nonceString)
        {
            _logger.Debug("Entering share constructor: {0}", nonceString);
            Miner = miner;
            JobId = jobId;
            Job   = job;
            Error = ShareError.None;

            var submitTime = TimeHelpers.NowInUnixTimestamp(); // time we recieved the share from miner.

            if (Job == null)
            {
                _logger.Error("Job is null");
                Error = ShareError.JobNotFound;
                return;
            }

            if (extraNonce2 == null)
            {
                _logger.Error("extraNonce2 is NULL!");
            }

            // check size of miner supplied extraNonce2
            if (extraNonce2.Length / 2 != ExtraNonce.ExpectedExtraNonce2Size)
            {
                _logger.Error("Incorrect Extranonce2 size: {0} while expecting {1}", extraNonce2.Length, ExtraNonce.ExpectedExtraNonce2Size * 2);
                Error = ShareError.IncorrectExtraNonce2Size;
                return;
            }
            ExtraNonce2 = Convert.ToUInt32(extraNonce2, 16); // set extraNonce2 for the share.


            if (nTimeString == null)
            {
                _logger.Error("nTimeString is NULL!");
            }
            // check size of miner supplied nTime.
            if (nTimeString.Length != 8)
            {
                _logger.Error("nTimeString length !=8: {0}", nTimeString.Length);
                Error = ShareError.IncorrectNTimeSize;
                return;
            }
            NTime = Convert.ToUInt32(nTimeString, 16); // read ntime for the share

            // make sure NTime is within range.
            if (NTime < job.BlockTemplate.CurTime || NTime > submitTime + 7200)
            {
                _logger.Error("NTime Out Of Range!");
                Error = ShareError.NTimeOutOfRange;
                return;
            }


            if (nonceString == null)
            {
                _logger.Error("nonceString is NULL!");
            }
            // check size of miner supplied nonce.
            if (nonceString.Length != 8)
            {
                _logger.Error("nonceString.Length != 8: {0}", nonceString.Length);
                Error = ShareError.IncorrectNonceSize;
                return;
            }
            Nonce = Convert.ToUInt32(nonceString, 16); // nonce supplied by the miner for the share.

            if (miner == null)
            {
                _logger.Error("miner is NULL!");
            }

            // set job supplied parameters.
            Height      = job.BlockTemplate.Height; // associated job's block height.
            ExtraNonce1 = miner.ExtraNonce;         // extra nonce1 assigned to miner.

            // check for duplicate shares.
            if (!Job.RegisterShare(this)) // try to register share with the job and see if it's duplicated or not.
            {
                _logger.Error("Duplicate share: {0:l}", nonceString);
                Error = ShareError.DuplicateShare;
                return;
            }

            _logger.Debug("Serialize Share {0}", nonceString);
            // construct the coinbase.
            CoinbaseBuffer = Serializers.SerializeCoinbase(Job, ExtraNonce1, ExtraNonce2);
            CoinbaseHash   = Coin.Coinbase.Utils.HashCoinbase(CoinbaseBuffer);

            // create the merkle root.
            MerkleRoot = Job.MerkleTree.WithFirst(CoinbaseHash).ReverseBuffer();

            // create the block headers
            _logger.Debug("Getting Header buffer for Share {0}", nonceString);
            HeaderBuffer = Serializers.SerializeHeader(Job, MerkleRoot, NTime, Nonce);
            HeaderHash   = Job.HashAlgorithm.Hash(HeaderBuffer);
            _logger.Debug("Got share {0} of length: {1}\nPOW: {2,64:l}\nTGT: {3,64:l}", nonceString, HeaderHash.Length,
                          HeaderHash.ReverseBytes().ToHexString(), Job.Target.ToByteArray().ReverseBytes().ToHexString()
                          );
            HeaderValue = new BigInteger(HeaderHash);

            // calculate the share difficulty
            Difficulty = ((double)new BigRational(AlgorithmManager.Diff1, HeaderValue)) * Job.HashAlgorithm.Multiplier;

            // calculate the block difficulty
            BlockDiffAdjusted = Job.Difficulty * Job.HashAlgorithm.Multiplier;


            /*
             * Test false pozitive block candidates: negative bigints were the problem
             * byte[] testbytes = new byte[] {
             *  0xf7, 0xdf, 0xed, 0xbd,
             *  0x9a, 0x2b, 0xa5, 0x1f,
             *  0x7b, 0x0d, 0x68, 0x76,
             *  0xbe, 0x1f, 0x18, 0xd6,
             *  0x2d, 0x49, 0x94, 0x91,
             *  0x69, 0x11, 0x39, 0x41,
             *  0xdf, 0x1f, 0x25, 0xdb,
             *  0x9b, 0x4e, 0x97, 0xb7
             * };
             * string teststr = testbytes.ReverseBuffer().ToHexString();
             * HeaderValue = new BigInteger(testbytes);
             */

            // check if block candicate
            if (Job.Target >= HeaderValue)
            //if (true) //for Debug only
            {
                IsBlockCandidate = true;
                BlockHex         = Serializers.SerializeBlock(Job, HeaderBuffer, CoinbaseBuffer, miner.Pool.Config.Coin.Options.IsProofOfStakeHybrid);
                BlockHash        = HeaderBuffer.DoubleDigest().ReverseBuffer();

                try
                {
                    _logger.Debug("Job.Target is greater than or equal HeaderValue(POW-SCRYPT)!!!:\n{9}\n{10}\n\n" +
                                  "Big-Endian values for Block Header:\n" +
                                  "job.BlockTemplate.Version={0}\n" +
                                  "job.PreviousBlockHash={1}\n" +
                                  "MerkleRoot={2}\n" +
                                  "NTime={3}\n" +
                                  "job.EncodedDifficulty={4}\n" +
                                  "Nonce={5}\n" +
                                  "==============\n" +
                                  "result={6}\n\n" +
                                  "Big-Endian:\n" +
                                  "BlockHex={7}\n" +
                                  "BlockHash(2xSHA256)={8}\n",
                                  job.BlockTemplate.Version,
                                  BitConverter.ToString(job.PreviousBlockHash.HexToByteArray()).Replace("-", string.Empty),
                                  BitConverter.ToString(MerkleRoot).Replace("-", string.Empty),
                                  NTime,
                                  job.EncodedDifficulty,
                                  Nonce,
                                  BitConverter.ToString(HeaderBuffer).Replace("-", string.Empty),
                                  BlockHex,
                                  BitConverter.ToString(BlockHash).Replace("-", string.Empty),
                                  Job.Target.ToByteArray().ReverseBuffer().ToHexString(),
                                  HeaderValue.ToByteArray().ReverseBuffer().ToHexString()
                                  );
                }
                catch (Exception e)
                {
                    _logger.Error(e, "Something has happened while logging");
                }
            }
            else
            {
                IsBlockCandidate = false;
                BlockHash        = HeaderBuffer.DoubleDigest().ReverseBuffer();

                // Check if share difficulty reaches miner difficulty.
                var lowDifficulty = Difficulty / miner.Difficulty < 0.99; // share difficulty should be equal or more then miner's target difficulty.

                if (!lowDifficulty)                                       // if share difficulty is high enough to match miner's current difficulty.
                {
                    return;                                               // just accept the share.
                }
                if (Difficulty >= miner.PreviousDifficulty)               // if the difficulty matches miner's previous difficulty before the last vardiff triggered difficulty change
                {
                    return;                                               // still accept the share.
                }
                // if the share difficulty can't match miner's current difficulty or previous difficulty
                Error = ShareError.LowDifficultyShare; // then just reject the share with low difficult share error.
            }
        }