Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
glevco committed Mar 25, 2024
1 parent 3418cc7 commit 4540afe
Show file tree
Hide file tree
Showing 13 changed files with 73 additions and 80 deletions.
2 changes: 1 addition & 1 deletion hathor/feature_activation/bit_signaling_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ def _log_signal_bits(self, feature: Feature, enable_bit: bool, support: bool, no

def _get_signaling_features(self, block: Block) -> dict[Feature, Criteria]:
"""Given a specific block, return all features that are in a signaling state for that block."""
feature_descriptions = self._feature_service.get_bits_description(block=block)
feature_descriptions = self._feature_service.get_feature_info(block=block)
signaling_features = {
feature: description.criteria
for feature, description in feature_descriptions.items()
Expand Down
8 changes: 4 additions & 4 deletions hathor/feature_activation/feature_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
from typing import TYPE_CHECKING, TypeAlias

from hathor.feature_activation.feature import Feature
from hathor.feature_activation.model.feature_description import FeatureDescription
from hathor.feature_activation.model.feature_description import FeatureInfo
from hathor.feature_activation.model.feature_state import FeatureState
from hathor.feature_activation.settings import Settings as FeatureSettings

Expand Down Expand Up @@ -62,7 +62,7 @@ def is_signaling_mandatory_features(self, block: 'Block') -> BlockSignalingState
height = block.get_height()
offset_to_boundary = height % self._feature_settings.evaluation_interval
remaining_blocks = self._feature_settings.evaluation_interval - offset_to_boundary - 1
descriptions = self.get_bits_description(block=block)
descriptions = self.get_feature_info(block=block)

must_signal_features = (
feature for feature, description in descriptions.items()
Expand Down Expand Up @@ -188,10 +188,10 @@ def _calculate_new_state(

raise ValueError(f'Unknown previous state: {previous_state}')

def get_bits_description(self, *, block: 'Block') -> dict[Feature, FeatureDescription]:
def get_feature_info(self, *, block: 'Block') -> dict[Feature, FeatureInfo]:
"""Returns the criteria definition and feature state for all features at a certain block."""
return {
feature: FeatureDescription(
feature: FeatureInfo(
criteria=criteria,
state=self.get_state(block=block, feature=feature)
)
Expand Down
2 changes: 1 addition & 1 deletion hathor/feature_activation/model/feature_description.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from hathor.feature_activation.model.feature_state import FeatureState


class FeatureDescription(NamedTuple):
class FeatureInfo(NamedTuple):
"""Represents all information related to one feature, that is, its criteria and state."""
criteria: Criteria
state: FeatureState
4 changes: 4 additions & 0 deletions hathor/feature_activation/model/feature_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,7 @@ def get_signaling_states() -> set['FeatureState']:
support it or not through bit signals is valid during those states.
"""
return {FeatureState.STARTED, FeatureState.MUST_SIGNAL, FeatureState.LOCKED_IN}

def is_active(self) -> bool:
"""Return whether the state is active."""
return self is FeatureState.ACTIVE
2 changes: 1 addition & 1 deletion hathor/feature_activation/resources/feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ def get_block_features(self, request: Request) -> bytes:
return error.json_dumpb()

signal_bits = []
feature_descriptions = self._feature_service.get_bits_description(block=block)
feature_descriptions = self._feature_service.get_feature_info(block=block)

for feature, description in feature_descriptions.items():
if description.state not in FeatureState.get_signaling_states():
Expand Down
2 changes: 1 addition & 1 deletion hathor/manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -1077,7 +1077,7 @@ def _log_feature_states(self, vertex: BaseTransaction) -> None:
if not isinstance(vertex, Block):
return

feature_descriptions = self._feature_service.get_bits_description(block=vertex)
feature_descriptions = self._feature_service.get_feature_info(block=vertex)
state_by_feature = {
feature.value: description.state.value
for feature, description in feature_descriptions.items()
Expand Down
22 changes: 9 additions & 13 deletions hathor/verification/merge_mined_block_verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,29 +14,25 @@

from hathor.conf.settings import HathorSettings
from hathor.feature_activation.feature import Feature
from hathor.feature_activation.feature_service import FeatureService
from hathor.feature_activation.model.feature_description import FeatureInfo
from hathor.transaction import MergeMinedBlock


class MergeMinedBlockVerifier:
__slots__ = ('_settings', '_feature_service',)
__slots__ = ('_settings',)

def __init__(self, *, settings: HathorSettings, feature_service: FeatureService):
def __init__(self, *, settings: HathorSettings) -> None:
self._settings = settings
self._feature_service = feature_service

def verify_aux_pow(self, block: MergeMinedBlock) -> None:
def verify_aux_pow(self, block: MergeMinedBlock, feature_info: dict[Feature, FeatureInfo]) -> None:
""" Verify auxiliary proof-of-work (for merged mining).
"""
assert block.aux_pow is not None

is_feature_active = self._feature_service.is_feature_active(
block=block,
feature=Feature.INCREASE_MAX_MERKLE_PATH_LENGTH
)
max_merkle_path_length = (
self._settings.NEW_MAX_MERKLE_PATH_LENGTH if is_feature_active
else self._settings.OLD_MAX_MERKLE_PATH_LENGTH
)
max_merkle_path_length = self._settings.OLD_MAX_MERKLE_PATH_LENGTH
merkle_path_info = feature_info.get(Feature.INCREASE_MAX_MERKLE_PATH_LENGTH)

if merkle_path_info and merkle_path_info.state.is_active():
max_merkle_path_length = self._settings.NEW_MAX_MERKLE_PATH_LENGTH

block.aux_pow.verify(block.get_base_hash(), max_merkle_path_length)
14 changes: 11 additions & 3 deletions hathor/verification/verification_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@

from typing_extensions import assert_never

from hathor.feature_activation.feature import Feature
from hathor.feature_activation.feature_service import BlockSignalingState, FeatureService
from hathor.feature_activation.model.feature_description import FeatureInfo
from hathor.profiler import get_cpu_profiler
from hathor.transaction import BaseTransaction, Block, MergeMinedBlock, Transaction, TxVersion
from hathor.transaction.token_creation_tx import TokenCreationTransaction
Expand Down Expand Up @@ -136,7 +138,8 @@ def verify(self, vertex: BaseTransaction, *, reject_locked_reward: bool = True)
case TxVersion.MERGE_MINED_BLOCK:
assert type(vertex) is MergeMinedBlock
signaling_state = self._feature_service.is_signaling_mandatory_features(vertex)
self._verify_merge_mined_block(vertex, signaling_state)
feature_info = self._feature_service.get_feature_info(block=vertex)
self._verify_merge_mined_block(vertex, signaling_state, feature_info)
case TxVersion.REGULAR_TRANSACTION:
assert type(vertex) is Transaction
self._verify_tx(vertex, reject_locked_reward=reject_locked_reward)
Expand Down Expand Up @@ -170,7 +173,13 @@ def _verify_block(self, block: Block, signaling_state: BlockSignalingState) -> N

self.verifiers.block.verify_mandatory_signaling(signaling_state)

def _verify_merge_mined_block(self, block: MergeMinedBlock, signaling_state: BlockSignalingState) -> None:
def _verify_merge_mined_block(
self,
block: MergeMinedBlock,
signaling_state: BlockSignalingState,
feature_info: dict[Feature, FeatureInfo]
) -> None:
self.verifiers.merge_mined_block.verify_aux_pow(block, feature_info)
self._verify_block(block, signaling_state)

@cpu.profiler(key=lambda _, tx: 'tx-verify!{}'.format(tx.hash.hex()))
Expand Down Expand Up @@ -242,7 +251,6 @@ def _verify_without_storage_block(self, block: Block) -> None:
self.verifiers.vertex.verify_sigops_output(block)

def _verify_without_storage_merge_mined_block(self, block: MergeMinedBlock) -> None:
self.verifiers.merge_mined_block.verify_aux_pow(block)
self._verify_without_storage_block(block)

def _verify_without_storage_tx(self, tx: Transaction) -> None:
Expand Down
30 changes: 15 additions & 15 deletions tests/feature_activation/test_bit_signaling_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
from hathor.feature_activation.feature import Feature
from hathor.feature_activation.feature_service import FeatureService
from hathor.feature_activation.model.criteria import Criteria
from hathor.feature_activation.model.feature_description import FeatureDescription
from hathor.feature_activation.model.feature_description import FeatureInfo
from hathor.feature_activation.model.feature_state import FeatureState
from hathor.feature_activation.settings import Settings as FeatureSettings
from hathor.transaction import Block
Expand All @@ -32,11 +32,11 @@
[
{},
{
Feature.NOP_FEATURE_1: FeatureDescription(state=FeatureState.DEFINED, criteria=Mock())
Feature.NOP_FEATURE_1: FeatureInfo(state=FeatureState.DEFINED, criteria=Mock())
},
{
Feature.NOP_FEATURE_1: FeatureDescription(state=FeatureState.FAILED, criteria=Mock()),
Feature.NOP_FEATURE_2: FeatureDescription(state=FeatureState.ACTIVE, criteria=Mock())
Feature.NOP_FEATURE_1: FeatureInfo(state=FeatureState.FAILED, criteria=Mock()),
Feature.NOP_FEATURE_2: FeatureInfo(state=FeatureState.ACTIVE, criteria=Mock())
}
]
)
Expand All @@ -50,7 +50,7 @@
]
)
def test_generate_signal_bits_no_signaling_features(
features_description: dict[Feature, FeatureDescription],
features_description: dict[Feature, FeatureInfo],
support_features: set[Feature],
not_support_features: set[Feature]
) -> None:
Expand All @@ -74,7 +74,7 @@ def test_generate_signal_bits_signaling_features(
expected_signal_bits: int,
) -> None:
features_description = {
Feature.NOP_FEATURE_1: FeatureDescription(
Feature.NOP_FEATURE_1: FeatureInfo(
state=FeatureState.STARTED,
criteria=Criteria(
bit=0,
Expand All @@ -83,7 +83,7 @@ def test_generate_signal_bits_signaling_features(
version='0.0.0'
)
),
Feature.NOP_FEATURE_2: FeatureDescription(
Feature.NOP_FEATURE_2: FeatureInfo(
state=FeatureState.MUST_SIGNAL,
criteria=Criteria(
bit=1,
Expand All @@ -92,7 +92,7 @@ def test_generate_signal_bits_signaling_features(
version='0.0.0'
)
),
Feature.NOP_FEATURE_3: FeatureDescription(
Feature.NOP_FEATURE_3: FeatureInfo(
state=FeatureState.LOCKED_IN,
criteria=Criteria(
bit=3,
Expand Down Expand Up @@ -124,7 +124,7 @@ def test_generate_signal_bits_signaling_features_with_defaults(
expected_signal_bits: int,
) -> None:
features_description = {
Feature.NOP_FEATURE_1: FeatureDescription(
Feature.NOP_FEATURE_1: FeatureInfo(
state=FeatureState.STARTED,
criteria=Criteria(
bit=0,
Expand All @@ -134,7 +134,7 @@ def test_generate_signal_bits_signaling_features_with_defaults(
signal_support_by_default=True
)
),
Feature.NOP_FEATURE_2: FeatureDescription(
Feature.NOP_FEATURE_2: FeatureInfo(
state=FeatureState.MUST_SIGNAL,
criteria=Criteria(
bit=1,
Expand All @@ -144,7 +144,7 @@ def test_generate_signal_bits_signaling_features_with_defaults(
signal_support_by_default=True
)
),
Feature.NOP_FEATURE_3: FeatureDescription(
Feature.NOP_FEATURE_3: FeatureInfo(
state=FeatureState.LOCKED_IN,
criteria=Criteria(
bit=3,
Expand All @@ -161,12 +161,12 @@ def test_generate_signal_bits_signaling_features_with_defaults(


def _test_generate_signal_bits(
features_description: dict[Feature, FeatureDescription],
features_description: dict[Feature, FeatureInfo],
support_features: set[Feature],
not_support_features: set[Feature]
) -> int:
feature_service = Mock(spec_set=FeatureService)
feature_service.get_bits_description = lambda block: features_description
feature_service.get_feature_info = lambda block: features_description

service = BitSignalingService(
feature_settings=FeatureSettings(),
Expand Down Expand Up @@ -258,13 +258,13 @@ def test_non_signaling_features_warning(
tx_storage = Mock(spec_set=TransactionStorage)
tx_storage.get_best_block = lambda: best_block

def get_bits_description_mock(block: Block) -> dict[Feature, FeatureDescription]:
def get_feature_info_mock(block: Block) -> dict[Feature, FeatureInfo]:
if block == best_block:
return {}
raise NotImplementedError

feature_service = Mock(spec_set=FeatureService)
feature_service.get_bits_description = get_bits_description_mock
feature_service.get_feature_info = get_feature_info_mock

service = BitSignalingService(
feature_settings=FeatureSettings(),
Expand Down
8 changes: 4 additions & 4 deletions tests/feature_activation/test_feature_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
FeatureService,
)
from hathor.feature_activation.model.criteria import Criteria
from hathor.feature_activation.model.feature_description import FeatureDescription
from hathor.feature_activation.model.feature_description import FeatureInfo
from hathor.feature_activation.model.feature_state import FeatureState
from hathor.feature_activation.settings import Settings as FeatureSettings
from hathor.transaction import Block, TransactionMetadata
Expand Down Expand Up @@ -568,11 +568,11 @@ def get_state(self: FeatureService, *, block: Block, feature: Feature) -> Featur
return states[feature]

with patch('hathor.feature_activation.feature_service.FeatureService.get_state', get_state):
result = service.get_bits_description(block=Mock())
result = service.get_feature_info(block=Mock())

expected = {
Feature.NOP_FEATURE_1: FeatureDescription(criteria_mock_1, FeatureState.STARTED),
Feature.NOP_FEATURE_2: FeatureDescription(criteria_mock_2, FeatureState.FAILED),
Feature.NOP_FEATURE_1: FeatureInfo(criteria_mock_1, FeatureState.STARTED),
Feature.NOP_FEATURE_2: FeatureInfo(criteria_mock_2, FeatureState.FAILED),
}

assert result == expected
Expand Down
6 changes: 3 additions & 3 deletions tests/resources/feature/test_feature.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
from hathor.feature_activation.feature import Feature
from hathor.feature_activation.feature_service import FeatureService
from hathor.feature_activation.model.criteria import Criteria
from hathor.feature_activation.model.feature_description import FeatureDescription
from hathor.feature_activation.model.feature_description import FeatureInfo
from hathor.feature_activation.model.feature_state import FeatureState
from hathor.feature_activation.resources.feature import FeatureResource
from hathor.feature_activation.settings import Settings as FeatureSettings
Expand Down Expand Up @@ -59,8 +59,8 @@ def get_state(*, block: Block, feature: Feature) -> FeatureState:
feature_service = Mock(spec_set=FeatureService)
feature_service.get_state = Mock(side_effect=get_state)
feature_service.get_bits_description = Mock(return_value={
Feature.NOP_FEATURE_1: FeatureDescription(state=FeatureState.DEFINED, criteria=nop_feature_1_criteria),
Feature.NOP_FEATURE_2: FeatureDescription(state=FeatureState.LOCKED_IN, criteria=nop_feature_2_criteria),
Feature.NOP_FEATURE_1: FeatureInfo(state=FeatureState.DEFINED, criteria=nop_feature_1_criteria),
Feature.NOP_FEATURE_2: FeatureInfo(state=FeatureState.LOCKED_IN, criteria=nop_feature_2_criteria),
})

feature_settings = FeatureSettings(
Expand Down
Loading

0 comments on commit 4540afe

Please sign in to comment.