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 } }