@@ -209,36 +209,46 @@ def seconds_to_hms(s):
209209 out = "-" + out
210210 return out
211211
212- def next_block_delta (last_nbits , last_hash , ultimate_target , do_poisson , max_interval ):
213- # strategy:
214- # 1) work out how far off our desired target we are
215- # 2) cap it to a factor of 4 since that's the best we can do in a single retarget period
216- # 3) use that to work out the desired average interval in this retarget period
217- # 4) if doing poisson, use the last hash to pick a uniformly random number in [0,1), and work out a random multiplier to vary the average by
218- # 5) cap the resulting interval between 1 second and 1 hour to avoid extremes
219-
212+ class Generate :
220213 INTERVAL = 600.0 * 2016 / 2015 # 10 minutes, adjusted for the off-by-one bug
221214
222- current_target = nbits_to_target (last_nbits )
223- retarget_factor = ultimate_target / current_target
224- retarget_factor = max (0.25 , min (retarget_factor , 4.0 ))
225215
226- avg_interval = INTERVAL * retarget_factor
216+ def __init__ (self , multiminer = None , ultimate_target = None , poisson = False , max_interval = 1800 ):
217+ if multiminer is None :
218+ multiminer = (0 , 1 , 1 )
219+ (self .multi_low , self .multi_high , self .multi_period ) = multiminer
220+ self .ultimate_target = ultimate_target
221+ self .poisson = poisson
222+ self .max_interval = max_interval
227223
228- if do_poisson :
229- det_rand = int (last_hash [- 8 :], 16 ) * 2 ** - 32
230- this_interval_variance = - math .log1p (- det_rand )
231- else :
232- this_interval_variance = 1
224+ def next_block_delta (self , last_nbits , last_hash ):
225+ # strategy:
226+ # 1) work out how far off our desired target we are
227+ # 2) cap it to a factor of 4 since that's the best we can do in a single retarget period
228+ # 3) use that to work out the desired average interval in this retarget period
229+ # 4) if doing poisson, use the last hash to pick a uniformly random number in [0,1), and work out a random multiplier to vary the average by
230+ # 5) cap the resulting interval between 1 second and 1 hour to avoid extremes
233231
234- this_interval = avg_interval * this_interval_variance
235- this_interval = max (1 , min (this_interval , max_interval ))
232+ current_target = nbits_to_target (last_nbits )
233+ retarget_factor = self .ultimate_target / current_target
234+ retarget_factor = max (0.25 , min (retarget_factor , 4.0 ))
236235
237- return this_interval
236+ avg_interval = self .INTERVAL * retarget_factor
237+
238+ if self .poisson :
239+ det_rand = int (last_hash [- 8 :], 16 ) * 2 ** - 32
240+ this_interval_variance = - math .log1p (- det_rand )
241+ else :
242+ this_interval_variance = 1
238243
239- def next_block_is_mine (last_hash , my_blocks ):
240- det_rand = int (last_hash [- 16 :- 8 ], 16 )
241- return my_blocks [0 ] <= (det_rand % my_blocks [2 ]) < my_blocks [1 ]
244+ this_interval = avg_interval * this_interval_variance
245+ this_interval = max (1 , min (this_interval , self .max_interval ))
246+
247+ return this_interval
248+
249+ def next_block_is_mine (self , last_hash ):
250+ det_rand = int (last_hash [- 16 :- 8 ], 16 )
251+ return self .multi_low <= (det_rand % self .multi_period ) < self .multi_high
242252
243253def do_generate (args ):
244254 if args .max_blocks is not None :
@@ -298,6 +308,8 @@ def do_generate(args):
298308
299309 ultimate_target = nbits_to_target (int (args .nbits ,16 ))
300310
311+ gen = Generate (multiminer = my_blocks , ultimate_target = ultimate_target , poisson = args .poisson , max_interval = args .max_interval )
312+
301313 mined_blocks = 0
302314 bestheader = {"hash" : None }
303315 lastheader = None
@@ -312,9 +324,9 @@ def do_generate(args):
312324 if lastheader is None :
313325 lastheader = bestheader ["hash" ]
314326 elif bestheader ["hash" ] != lastheader :
315- next_delta = next_block_delta (int (bestheader ["bits" ], 16 ), bestheader ["hash" ], ultimate_target , args . poisson , args . max_interval )
327+ next_delta = gen . next_block_delta (int (bestheader ["bits" ], 16 ), bestheader ["hash" ])
316328 next_delta += bestheader ["time" ] - time .time ()
317- next_is_mine = next_block_is_mine (bestheader ["hash" ], my_blocks )
329+ next_is_mine = gen . next_block_is_mine (bestheader ["hash" ])
318330 logging .info ("Received new block at height %d; next in %s (%s)" , bestheader ["height" ], seconds_to_hms (next_delta ), ("mine" if next_is_mine else "backup" ))
319331 lastheader = bestheader ["hash" ]
320332
@@ -326,17 +338,17 @@ def do_generate(args):
326338 action_time = now
327339 is_mine = True
328340 elif bestheader ["height" ] == 0 :
329- time_delta = next_block_delta (int (bestheader ["bits" ], 16 ), bci ["bestblockhash" ], ultimate_target , args . poisson , args . max_interval )
341+ time_delta = gen . next_block_delta (int (bestheader ["bits" ], 16 ), bci ["bestblockhash" ])
330342 time_delta *= 100 # 100 blocks
331343 logging .info ("Backdating time for first block to %d minutes ago" % (time_delta / 60 ))
332344 mine_time = now - time_delta
333345 action_time = now
334346 is_mine = True
335347 else :
336- time_delta = next_block_delta (int (bestheader ["bits" ], 16 ), bci ["bestblockhash" ], ultimate_target , args . poisson , args . max_interval )
348+ time_delta = gen . next_block_delta (int (bestheader ["bits" ], 16 ), bci ["bestblockhash" ])
337349 mine_time = bestheader ["time" ] + time_delta
338350
339- is_mine = next_block_is_mine (bci ["bestblockhash" ], my_blocks )
351+ is_mine = gen . next_block_is_mine (bci ["bestblockhash" ])
340352
341353 action_time = mine_time
342354 if not is_mine :
@@ -407,9 +419,9 @@ def do_generate(args):
407419 # report
408420 bstr = "block" if is_mine else "backup block"
409421
410- next_delta = next_block_delta (block .nBits , block .hash , ultimate_target , args . poisson , args . max_interval )
422+ next_delta = gen . next_block_delta (block .nBits , block .hash )
411423 next_delta += block .nTime - time .time ()
412- next_is_mine = next_block_is_mine (block .hash , my_blocks )
424+ next_is_mine = gen . next_block_is_mine (block .hash )
413425
414426 logging .debug ("Block hash %s payout to %s" , block .hash , reward_addr )
415427 logging .info ("Mined %s at height %d; next in %s (%s)" , bstr , tmpl ["height" ], seconds_to_hms (next_delta ), ("mine" if next_is_mine else "backup" ))
0 commit comments