@@ -209,36 +209,46 @@ def seconds_to_hms(s):
209
209
out = "-" + out
210
210
return out
211
211
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 :
220
213
INTERVAL = 600.0 * 2016 / 2015 # 10 minutes, adjusted for the off-by-one bug
221
214
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 ))
225
215
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
227
223
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
233
231
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 ))
236
235
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
238
243
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
242
252
243
253
def do_generate (args ):
244
254
if args .max_blocks is not None :
@@ -298,6 +308,8 @@ def do_generate(args):
298
308
299
309
ultimate_target = nbits_to_target (int (args .nbits ,16 ))
300
310
311
+ gen = Generate (multiminer = my_blocks , ultimate_target = ultimate_target , poisson = args .poisson , max_interval = args .max_interval )
312
+
301
313
mined_blocks = 0
302
314
bestheader = {"hash" : None }
303
315
lastheader = None
@@ -312,9 +324,9 @@ def do_generate(args):
312
324
if lastheader is None :
313
325
lastheader = bestheader ["hash" ]
314
326
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" ])
316
328
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" ])
318
330
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" ))
319
331
lastheader = bestheader ["hash" ]
320
332
@@ -326,17 +338,17 @@ def do_generate(args):
326
338
action_time = now
327
339
is_mine = True
328
340
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" ])
330
342
time_delta *= 100 # 100 blocks
331
343
logging .info ("Backdating time for first block to %d minutes ago" % (time_delta / 60 ))
332
344
mine_time = now - time_delta
333
345
action_time = now
334
346
is_mine = True
335
347
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" ])
337
349
mine_time = bestheader ["time" ] + time_delta
338
350
339
- is_mine = next_block_is_mine (bci ["bestblockhash" ], my_blocks )
351
+ is_mine = gen . next_block_is_mine (bci ["bestblockhash" ])
340
352
341
353
action_time = mine_time
342
354
if not is_mine :
@@ -407,9 +419,9 @@ def do_generate(args):
407
419
# report
408
420
bstr = "block" if is_mine else "backup block"
409
421
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 )
411
423
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 )
413
425
414
426
logging .debug ("Block hash %s payout to %s" , block .hash , reward_addr )
415
427
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