List <MinerContext> CreateMinerContexts(int minerCount) { BitcoinWitPubKeyAddress[] mineToAddresses = AddressCache.GetMineToAddresses(minerCount); var contexts = new List <MinerContext>(minerCount); for (int i = 0; i < minerCount; i++) { // if the device index is disabled by configuration, don't create MinerContext if (this.appConfiguration.DisabledDeviceIndices.Contains(i)) { continue; } // this gets us the latest block template, including a unique extra nonce var blockTemplate = this.blockTemplateCache.GetClonedBlockTemplateLocked(); // calculate the start value for block time var earliestTimeVsTime = blockTemplate.curtime + 1; // curtime takes into account adjusted time and prev block median time past var earliestTimeVsPrevTime = blockTemplate.previousblocktime + 1; // x1 consensus requires the block time > last block time var newPoWBlockMinTime = Math.Max(earliestTimeVsTime, earliestTimeVsPrevTime); // time is guaranteed to be > time(prev block) and most likely curtime +1 // the header of this block is complete, with the lowest valid time, and a nonce of 0 var block = blockTemplate.CreateTemplateBlock(newPoWBlockMinTime, false, mineToAddresses[i].ScriptPubKey, null, null); var minerContext = new MinerContext { Name = $"{this.appConfiguration.ClientId} #{i}", ThreadStartedUtc = DateTime.UtcNow, StartNonce = 0, MaxNonce = uint.MaxValue - 1, ThreadIndex = i, SlimBlock = block }; contexts.Add(minerContext); if (!this.deviceController.PerfCounters.ContainsKey(i)) { this.deviceController.PerfCounters.TryAdd(i, new PerfCounter()); } } return(contexts); }