public Share(IStratumMiner miner, UInt64 jobId, IJob job, string extraNonce2, string nTimeString, string nonceString) { Miner = miner; JobId = jobId; Job = job; Error = ShareError.None; UInt64 submitTime = TimeHelpers.NowInUnixTime64(); // 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 != 16) { Error = ShareError.IncorrectNTimeSize; return; } NTime = Convert.ToUInt64(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 != 16) { Error = ShareError.IncorrectNonceSize; return; } Nonce = Convert.ToUInt64(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); var coinbaseNoSigBuffer = Serializers.SerializeCoinbaseForTxId(Job, ExtraNonce1, ExtraNonce2); CoinbaseTxId = Coin.Coinbase.Utils.HashCoinbase(coinbaseNoSigBuffer); // create the merkle root. MerkleRoot = Job.MerkleTree.WithFirst(CoinbaseHash).ReverseBuffer(); // create the block headers HeaderBuffer = Serializers.SerializeHeader(Job, MerkleRoot, NTime, Nonce); HeaderBufferForHash = Serializers.SerializeHeaderForHash(Job, MerkleRoot, NTime, Nonce); HeaderHash = Job.HashAlgorithm.Hash(HeaderBufferForHash, miner.Pool.Config.Coin.Options); HeaderHashValue = new BigInteger(HeaderHash); // calculate the share difficulty Difficulty = ((double)new BigRational(Algorithms.Diff1, HeaderHashValue)) * Job.HashAlgorithm.Multiplier; BigInteger minerTarget = (new BigRational(Algorithms.Diff1, new BigInteger((uint)miner.Difficulty)) * Job.HashAlgorithm.Multiplier).GetWholePart(); // calculate the block difficulty BlockDiffAdjusted = Job.Difficulty * Job.HashAlgorithm.Multiplier; // check if block candicate if (Job.Target >= HeaderHashValue) { IsBlockCandidate = true; BlockHex = Serializers.SerializeBlock(Job, HeaderBuffer, CoinbaseBuffer); BlockHash = HeaderHash.ReverseBuffer(); //HeaderBuffer.DoubleDigest().ReverseBuffer(); // TODO: make sure this is okay! } else { IsBlockCandidate = false; BlockHash = HeaderHash.ReverseBuffer();//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. } }