signet/miner: add Generate.next_block_time function
This commit is contained in:
1 parent
5540e6ca49
commit
85c5c0bea9
1 file changed
+57
-50
+57
-50
@@ -213,13 +213,17 @@ class Generate:
|
|||||||
INTERVAL = 600.0*2016/2015 # 10 minutes, adjusted for the off-by-one bug
|
INTERVAL = 600.0*2016/2015 # 10 minutes, adjusted for the off-by-one bug
|
||||||
|
|
||||||
|
|
||||||
def __init__(self, multiminer=None, ultimate_target=None, poisson=False, max_interval=1800):
|
def __init__(self, multiminer=None, ultimate_target=None, poisson=False, max_interval=1800,
|
||||||
|
standby_delay=0, backup_delay=0, set_block_time=None):
|
||||||
if multiminer is None:
|
if multiminer is None:
|
||||||
multiminer = (0, 1, 1)
|
multiminer = (0, 1, 1)
|
||||||
(self.multi_low, self.multi_high, self.multi_period) = multiminer
|
(self.multi_low, self.multi_high, self.multi_period) = multiminer
|
||||||
self.ultimate_target = ultimate_target
|
self.ultimate_target = ultimate_target
|
||||||
self.poisson = poisson
|
self.poisson = poisson
|
||||||
self.max_interval = max_interval
|
self.max_interval = max_interval
|
||||||
|
self.standby_delay = standby_delay
|
||||||
|
self.backup_delay = backup_delay
|
||||||
|
self.set_block_time = set_block_time
|
||||||
|
|
||||||
def next_block_delta(self, last_nbits, last_hash):
|
def next_block_delta(self, last_nbits, last_hash):
|
||||||
# strategy:
|
# strategy:
|
||||||
@@ -250,6 +254,42 @@ class Generate:
|
|||||||
det_rand = int(last_hash[-16:-8], 16)
|
det_rand = int(last_hash[-16:-8], 16)
|
||||||
return self.multi_low <= (det_rand % self.multi_period) < self.multi_high
|
return self.multi_low <= (det_rand % self.multi_period) < self.multi_high
|
||||||
|
|
||||||
|
def next_block_time(self, now, bestheader, is_first_block):
|
||||||
|
if self.set_block_time is not None:
|
||||||
|
logging.debug("Setting start time to %d", self.set_block_time)
|
||||||
|
self.mine_time = self.set_block_time
|
||||||
|
self.action_time = now
|
||||||
|
self.is_mine = True
|
||||||
|
elif bestheader["height"] == 0:
|
||||||
|
time_delta = self.INTERVAL * 100 # plenty of time to mine 100 blocks
|
||||||
|
logging.info("Backdating time for first block to %d minutes ago" % (time_delta/60))
|
||||||
|
self.mine_time = now - time_delta
|
||||||
|
self.action_time = now
|
||||||
|
self.is_mine = True
|
||||||
|
else:
|
||||||
|
time_delta = self.next_block_delta(int(bestheader["bits"], 16), bestheader["hash"])
|
||||||
|
self.mine_time = bestheader["time"] + time_delta
|
||||||
|
|
||||||
|
self.is_mine = self.next_block_is_mine(bestheader["hash"])
|
||||||
|
|
||||||
|
self.action_time = self.mine_time
|
||||||
|
if not self.is_mine:
|
||||||
|
self.action_time += self.backup_delay
|
||||||
|
|
||||||
|
if self.standby_delay > 0:
|
||||||
|
self.action_time += self.standby_delay
|
||||||
|
elif is_first_block:
|
||||||
|
# for non-standby, always mine immediately on startup,
|
||||||
|
# even if the next block shouldn't be ours
|
||||||
|
self.action_time = now
|
||||||
|
|
||||||
|
# don't want fractional times so round down
|
||||||
|
self.mine_time = int(self.mine_time)
|
||||||
|
self.action_time = int(self.action_time)
|
||||||
|
|
||||||
|
# can't mine a block 2h in the future; 1h55m for some safety
|
||||||
|
self.action_time = max(self.action_time, self.mine_time - 6900)
|
||||||
|
|
||||||
def do_generate(args):
|
def do_generate(args):
|
||||||
if args.max_blocks is not None:
|
if args.max_blocks is not None:
|
||||||
if args.ongoing:
|
if args.ongoing:
|
||||||
@@ -308,7 +348,8 @@ def do_generate(args):
|
|||||||
|
|
||||||
ultimate_target = nbits_to_target(int(args.nbits,16))
|
ultimate_target = nbits_to_target(int(args.nbits,16))
|
||||||
|
|
||||||
gen = Generate(multiminer=my_blocks, ultimate_target=ultimate_target, poisson=args.poisson, max_interval=args.max_interval)
|
gen = Generate(multiminer=my_blocks, ultimate_target=ultimate_target, poisson=args.poisson, max_interval=args.max_interval,
|
||||||
|
standby_delay=args.standby_delay, backup_delay=args.backup_delay, set_block_time=args.set_block_time)
|
||||||
|
|
||||||
mined_blocks = 0
|
mined_blocks = 0
|
||||||
bestheader = {"hash": None}
|
bestheader = {"hash": None}
|
||||||
@@ -332,52 +373,18 @@ def do_generate(args):
|
|||||||
|
|
||||||
# when is the next block due to be mined?
|
# when is the next block due to be mined?
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if args.set_block_time is not None:
|
gen.next_block_time(now, bestheader, (mined_blocks == 0))
|
||||||
logging.debug("Setting start time to %d", args.set_block_time)
|
|
||||||
mine_time = args.set_block_time
|
|
||||||
action_time = now
|
|
||||||
is_mine = True
|
|
||||||
elif bestheader["height"] == 0:
|
|
||||||
time_delta = gen.next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"])
|
|
||||||
time_delta *= 100 # 100 blocks
|
|
||||||
logging.info("Backdating time for first block to %d minutes ago" % (time_delta/60))
|
|
||||||
mine_time = now - time_delta
|
|
||||||
action_time = now
|
|
||||||
is_mine = True
|
|
||||||
else:
|
|
||||||
time_delta = gen.next_block_delta(int(bestheader["bits"], 16), bci["bestblockhash"])
|
|
||||||
mine_time = bestheader["time"] + time_delta
|
|
||||||
|
|
||||||
is_mine = gen.next_block_is_mine(bci["bestblockhash"])
|
|
||||||
|
|
||||||
action_time = mine_time
|
|
||||||
if not is_mine:
|
|
||||||
action_time += args.backup_delay
|
|
||||||
|
|
||||||
if args.standby_delay > 0:
|
|
||||||
action_time += args.standby_delay
|
|
||||||
elif mined_blocks == 0:
|
|
||||||
# for non-standby, always mine immediately on startup,
|
|
||||||
# even if the next block shouldn't be ours
|
|
||||||
action_time = now
|
|
||||||
|
|
||||||
# don't want fractional times so round down
|
|
||||||
mine_time = int(mine_time)
|
|
||||||
action_time = int(action_time)
|
|
||||||
|
|
||||||
# can't mine a block 2h in the future; 1h55m for some safety
|
|
||||||
action_time = max(action_time, mine_time - 6900)
|
|
||||||
|
|
||||||
# ready to go? otherwise sleep and check for new block
|
# ready to go? otherwise sleep and check for new block
|
||||||
if now < action_time:
|
if now < gen.action_time:
|
||||||
sleep_for = min(action_time - now, 60)
|
sleep_for = min(gen.action_time - now, 60)
|
||||||
if mine_time < now:
|
if gen.mine_time < now:
|
||||||
# someone else might have mined the block,
|
# someone else might have mined the block,
|
||||||
# so check frequently, so we don't end up late
|
# so check frequently, so we don't end up late
|
||||||
# mining the next block if it's ours
|
# mining the next block if it's ours
|
||||||
sleep_for = min(20, sleep_for)
|
sleep_for = min(20, sleep_for)
|
||||||
minestr = "mine" if is_mine else "backup"
|
minestr = "mine" if gen.is_mine else "backup"
|
||||||
logging.debug("Sleeping for %s, next block due in %s (%s)" % (seconds_to_hms(sleep_for), seconds_to_hms(mine_time - now), minestr))
|
logging.debug("Sleeping for %s, next block due in %s (%s)" % (seconds_to_hms(sleep_for), seconds_to_hms(gen.mine_time - now), minestr))
|
||||||
time.sleep(sleep_for)
|
time.sleep(sleep_for)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -390,20 +397,20 @@ def do_generate(args):
|
|||||||
|
|
||||||
logging.debug("GBT template: %s", tmpl)
|
logging.debug("GBT template: %s", tmpl)
|
||||||
|
|
||||||
if tmpl["mintime"] > mine_time:
|
if tmpl["mintime"] > gen.mine_time:
|
||||||
logging.info("Updating block time from %d to %d", mine_time, tmpl["mintime"])
|
logging.info("Updating block time from %d to %d", gen.mine_time, tmpl["mintime"])
|
||||||
mine_time = tmpl["mintime"]
|
gen.mine_time = tmpl["mintime"]
|
||||||
if mine_time > now:
|
if gen.mine_time > now:
|
||||||
logging.error("GBT mintime is in the future: %d is %d seconds later than %d", mine_time, (mine_time-now), now)
|
logging.error("GBT mintime is in the future: %d is %d seconds later than %d", gen.mine_time, (gen.mine_time-now), now)
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
# address for reward
|
# address for reward
|
||||||
reward_addr, reward_spk = get_reward_addr_spk(args, tmpl["height"])
|
reward_addr, reward_spk = get_reward_addr_spk(args, tmpl["height"])
|
||||||
|
|
||||||
# mine block
|
# mine block
|
||||||
logging.debug("Mining block delta=%s start=%s mine=%s", seconds_to_hms(mine_time-bestheader["time"]), mine_time, is_mine)
|
logging.debug("Mining block delta=%s start=%s mine=%s", seconds_to_hms(gen.mine_time-bestheader["time"]), gen.mine_time, gen.is_mine)
|
||||||
mined_blocks += 1
|
mined_blocks += 1
|
||||||
psbt = generate_psbt(tmpl, reward_spk, blocktime=mine_time)
|
psbt = generate_psbt(tmpl, reward_spk, blocktime=gen.mine_time)
|
||||||
input_stream = os.linesep.join([psbt, "true", "ALL"]).encode('utf8')
|
input_stream = os.linesep.join([psbt, "true", "ALL"]).encode('utf8')
|
||||||
psbt_signed = json.loads(args.bcli("-stdin", "walletprocesspsbt", input=input_stream))
|
psbt_signed = json.loads(args.bcli("-stdin", "walletprocesspsbt", input=input_stream))
|
||||||
if not psbt_signed.get("complete",False):
|
if not psbt_signed.get("complete",False):
|
||||||
@@ -417,7 +424,7 @@ def do_generate(args):
|
|||||||
r = args.bcli("-stdin", "submitblock", input=block.serialize().hex().encode('utf8'))
|
r = args.bcli("-stdin", "submitblock", input=block.serialize().hex().encode('utf8'))
|
||||||
|
|
||||||
# report
|
# report
|
||||||
bstr = "block" if is_mine else "backup block"
|
bstr = "block" if gen.is_mine else "backup block"
|
||||||
|
|
||||||
next_delta = gen.next_block_delta(block.nBits, block.hash)
|
next_delta = gen.next_block_delta(block.nBits, block.hash)
|
||||||
next_delta += block.nTime - time.time()
|
next_delta += block.nTime - time.time()
|
||||||
|
|||||||
Reference in new issue
Block a user