@@ -181,6 +181,27 @@ public virtual void InitializeMining()
181181 startAfter : TimeSpans . TenSeconds ) ;
182182 }
183183
184+ private IFederationMember DetermineExpectedMinerForTimestamp ( uint headerTime )
185+ {
186+ // When blocks are missing for given timestamps we have to determine whom was supposed to mine
187+ // by looking at the federation make-up at the time and whom mined last.
188+
189+ ChainedHeader prevBlockMined = this . consensusManager . Tip ;
190+ while ( prevBlockMined . Header . Time > headerTime )
191+ prevBlockMined = prevBlockMined . Previous ;
192+
193+ IFederationMember minerForBlock = this . federationHistory . GetFederationMemberForBlock ( prevBlockMined ) ;
194+ List < IFederationMember > federationAtBlock = this . federationHistory . GetFederationForBlock ( prevBlockMined ) ;
195+
196+ int offset = ( int ) ( ( headerTime - prevBlockMined . Header . Time ) / this . network . ConsensusOptions . TargetSpacingSeconds ) ;
197+
198+ int minerForBlockIndex = federationAtBlock . TakeWhile ( m => m . PubKey != minerForBlock . PubKey ) . Count ( ) ;
199+
200+ int expectedIndex = ( minerForBlockIndex + offset ) % federationAtBlock . Count ;
201+
202+ return federationAtBlock [ expectedIndex ] ;
203+ }
204+
184205 private void GatherMiningStatistics ( )
185206 {
186207 var log = new StringBuilder ( ) ;
@@ -231,69 +252,46 @@ private void GatherMiningStatistics()
231252
232253 uint currentSlotTime = ( uint ) this . dateTimeProvider . GetAdjustedTimeAsUnixTimestamp ( ) ;
233254 currentSlotTime -= currentSlotTime % this . network . ConsensusOptions . TargetSpacingSeconds ;
234- if ( currentHeader . Header . Time > currentSlotTime )
235- currentSlotTime = currentHeader . Header . Time ;
236-
237- // Determine the number of slots before this node will mine.
238- uint slotOffset = ( this . slotsManager . GetMiningTimestamp ( currentSlotTime ) - currentSlotTime ) / this . network . ConsensusOptions . TargetSpacingSeconds ;
239-
240- // Determine the current slot from that.
241- int mySlotIndex = modifiedFederation . FindIndex ( m => m . PubKey == this . federationManager . CurrentFederationKey ? . PubKey ) ;
242- int currentSlot = ( int ) ( mySlotIndex - slotOffset ) % modifiedFederation . Count ;
243- while ( currentSlot < 0 )
244- currentSlot += modifiedFederation . Count ;
245255
246256 // Determine the public key of the current slot.
247- PubKey pubKey = modifiedFederation [ currentSlot ] . PubKey ;
248-
257+ string pubKeyRepresentation ;
249258 // Iterate mining slots.
250- for ( int i = 0 ; i < maxDepth ; i ++ )
259+ for ( int i = 0 ; i < maxDepth ; i ++ , currentSlotTime -= this . network . ConsensusOptions . TargetSpacingSeconds )
251260 {
252- string pubKeyRepresentation = pubKey . ToString ( ) . Substring ( 0 , pubKeyTakeCharacters ) ;
253-
254- if ( pubKey == this . federationManager . CurrentFederationKey ? . PubKey )
255- pubKeyRepresentation = "█████" ;
261+ // Find the chained header for this slot.
262+ while ( currentHeader . Header . Time > currentSlotTime )
263+ currentHeader = currentHeader . Previous ;
256264
257265 // Mined in this slot?
258- if ( currentHeader . Header . Time == currentSlotTime )
259- {
260- if ( includeHeight )
261- log . Append ( $ "{ currentHeader . Height . ToString ( ) . PadLeft ( 7 ) } :{ pubKeyRepresentation } ") ;
262- else
263- log . Append ( $ "[{ pubKeyRepresentation } ] ") ;
266+ bool minedInThisSlot = currentHeader . Header . Time == currentSlotTime ;
264267
265- currentHeader = currentHeader . Previous ;
266- hitCount ++ ;
268+ PubKey pubKey = ( minedInThisSlot ?
269+ this . federationHistory . GetFederationMemberForBlock ( currentHeader ) :
270+ DetermineExpectedMinerForTimestamp ( currentSlotTime ) ) . PubKey ;
267271
268- modifiedFederation = this . federationHistory . GetFederationForBlock ( currentHeader ) ;
269272
270- if ( pubKey == this . federationManager . CurrentFederationKey ? . PubKey )
271- this . miningStatistics . ProducedBlockInLastRound = true ;
273+ if ( pubKey == this . federationManager . CurrentFederationKey ? . PubKey )
274+ {
275+ pubKeyRepresentation = "█████" ;
276+ this . miningStatistics . ProducedBlockInLastRound = minedInThisSlot ;
272277 }
273278 else
274279 {
275- if ( includeHeight )
276- log . Append ( $ "---MISS:{ pubKeyRepresentation } ") ;
277- else
278- log . Append ( $ "<{ pubKeyRepresentation } > ") ;
279-
280- if ( pubKey == this . federationManager . CurrentFederationKey ? . PubKey )
281- this . miningStatistics . ProducedBlockInLastRound = false ;
280+ pubKeyRepresentation = pubKey . ToHex ( ) . Substring ( 0 , pubKeyTakeCharacters ) ;
282281 }
283282
284- // Determine previous miner.
285- int index = modifiedFederation . FindIndex ( m => m . PubKey . ToHex ( ) == pubKey . ToHex ( ) ) ;
286- if ( index < 0 )
283+ if ( includeHeight )
287284 {
288- // Federation changed.
289- log . Append ( $ "(Federation changed)") ;
290- break ;
285+ string strHeight = minedInThisSlot ? currentHeader . Height . ToString ( ) . PadLeft ( 7 ) : "---MISS" ;
286+ log . Append ( $ "{ strHeight } :{ pubKeyRepresentation } ") ;
287+ }
288+ else
289+ {
290+ log . Append ( minedInThisSlot ? $ "[{ pubKeyRepresentation } ] " : $ "<{ pubKeyRepresentation } > ") ;
291291 }
292292
293- index = ( index > 0 ) ? ( index - 1 ) : ( modifiedFederation . Count - 1 ) ;
294- pubKey = modifiedFederation [ index ] . PubKey ;
295-
296- currentSlotTime -= this . network . ConsensusOptions . TargetSpacingSeconds ;
293+ if ( minedInThisSlot )
294+ hitCount ++ ;
297295
298296 if ( ( ( i + 1 ) % ( includeHeight ? 10 : 20 ) ) == 0 )
299297 log . AppendLine ( ) ;
0 commit comments