Exemple #1
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);

            Console.WriteLine("Block header data: {0}", HeaderBuffer.ToHexString());

            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;
                    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.
                //Console.WriteLine("Miner difficulty:{0:0.000000000000000}", 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.

                miner.SetDifficulty(miner.Difficulty); // send miner difficulty again
            }
        }