Skip to content

fix(mining): Fix block template not checking for MAX_FUTURE_TIMESTAMP_ALLOWED #822

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions hathor/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ class BuilderError(Exception):
pass


class BlockTemplateError(Exception):
"""Base class for exceptions generating block template."""
pass


class BlockTemplateTimestampError(BlockTemplateError):
"""Raised when there is no timestamp available to prepare a block template."""
pass


class InvalidNewTransaction(HathorError):
"""Raised when a new received tx/block is not valid.
"""
Expand Down
8 changes: 8 additions & 0 deletions hathor/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
from hathor.consensus import ConsensusAlgorithm
from hathor.event.event_manager import EventManager
from hathor.exception import (
BlockTemplateTimestampError,
DoubleSpendingError,
HathorError,
InitializationError,
Expand Down Expand Up @@ -807,6 +808,13 @@ def _make_block_template(self, parent_block: Block, parent_txs: 'ParentTxs', cur
timestamp_max = min(timestamp_abs_max, timestamp_max_decay)
else:
timestamp_max = timestamp_abs_max
timestamp_max = min(timestamp_max, int(current_timestamp + self._settings.MAX_FUTURE_TIMESTAMP_ALLOWED))
if timestamp_max < timestamp_min:
raise BlockTemplateTimestampError(
f'Unable to create a block template because there is no timestamp available. '
f'(min={timestamp_min}, max={timestamp_max}) '
f'(current_timestamp={current_timestamp})'
)
timestamp = min(max(current_timestamp, timestamp_min), timestamp_max)
parent_block_metadata = parent_block.get_metadata()
# this is the min weight to cause an increase of twice the WEIGHT_TOL, we make sure to generate a template with
Expand Down
21 changes: 14 additions & 7 deletions hathor/simulator/miner/geometric_miner.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from typing import TYPE_CHECKING, Optional

from hathor.conf.get_settings import get_settings
from hathor.exception import BlockTemplateTimestampError
from hathor.manager import HathorEvents
from hathor.simulator.miner.abstract_miner import AbstractMiner
from hathor.util import Random
Expand Down Expand Up @@ -96,13 +97,19 @@ def _schedule_next_block(self):
self._block = None

if self._manager.can_start_mining():
block = self._generate_mining_block()
geometric_p = 2**(-block.weight)
trials = self._rng.geometric(geometric_p)
dt = 1.0 * trials / self._hashpower
self._block = block
self.log.debug('randomized step: start mining new block', dt=dt, parents=[h.hex() for h in block.parents],
block_timestamp=block.timestamp)
try:
block = self._generate_mining_block()
except BlockTemplateTimestampError:
dt = 5 # Try again in 5 seconds.
else:
geometric_p = 2**(-block.weight)
trials = self._rng.geometric(geometric_p)
dt = 1.0 * trials / self._hashpower
self._block = block
self.log.debug('randomized step: start mining new block',
dt=dt,
parents=[h.hex() for h in block.parents],
block_timestamp=block.timestamp)
else:
dt = 60

Expand Down
16 changes: 14 additions & 2 deletions tests/tx/test_mining.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,19 @@ def test_block_template_after_genesis(self) -> None:

block_templates = manager.get_block_templates()
self.assertEqual(len(block_templates), 1)

timestamp_max = min(
0xffffffff,
int(manager.reactor.seconds()) + self._settings.MAX_FUTURE_TIMESTAMP_ALLOWED
)

self.assertEqual(block_templates[0], BlockTemplate(
versions={0, 3},
reward=settings.INITIAL_TOKEN_UNITS_PER_BLOCK * 100,
weight=1.0,
timestamp_now=int(manager.reactor.seconds()),
timestamp_min=settings.GENESIS_BLOCK_TIMESTAMP + 3,
timestamp_max=0xffffffff, # no limit for next block after genesis
timestamp_max=timestamp_max, # no limit for next block after genesis
# parents=[tx.hash for tx in self.genesis_blocks + self.genesis_txs],
parents=block_templates[0].parents,
parents_any=[],
Expand All @@ -60,13 +66,19 @@ def test_regular_block_template(self) -> None:

block_templates = manager.get_block_templates()
self.assertEqual(len(block_templates), 1)

timestamp_max = min(
blocks[-1].timestamp + settings.MAX_DISTANCE_BETWEEN_BLOCKS - 1,
int(manager.reactor.seconds()) + self._settings.MAX_FUTURE_TIMESTAMP_ALLOWED
)

self.assertEqual(block_templates[0], BlockTemplate(
versions={0, 3},
reward=settings.INITIAL_TOKEN_UNITS_PER_BLOCK * 100,
weight=1.0,
timestamp_now=int(manager.reactor.seconds()),
timestamp_min=blocks[-1].timestamp + 1,
timestamp_max=blocks[-1].timestamp + settings.MAX_DISTANCE_BETWEEN_BLOCKS - 1,
timestamp_max=timestamp_max,
# parents=[blocks[-1].hash, self.genesis_txs[-1].hash, self.genesis_txs[-2].hash],
parents=block_templates[0].parents,
parents_any=[],
Expand Down