Skip to content

Commit cffe172

Browse files
authored
refactor(verification): remove BlockVerifier inheritance (#833)
1 parent 965fba3 commit cffe172

File tree

6 files changed

+128
-133
lines changed

6 files changed

+128
-133
lines changed

hathor/cli/mining.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -138,11 +138,12 @@ def execute(args: Namespace) -> None:
138138

139139
try:
140140
from hathor.daa import DifficultyAdjustmentAlgorithm
141-
from hathor.verification.block_verifier import BlockVerifier
141+
from hathor.verification.verification_service import VerificationService, VertexVerifiers
142142
settings = get_settings()
143143
daa = DifficultyAdjustmentAlgorithm(settings=settings)
144-
verifier = BlockVerifier(settings=settings, daa=daa)
145-
verifier.verify_without_storage(block)
144+
verifiers = VertexVerifiers.create_defaults(settings=settings, daa=daa)
145+
verification_service = VerificationService(verifiers=verifiers)
146+
verification_service.verify_without_storage(block)
146147
except HathorError:
147148
print('[{}] ERROR: Block has not been pushed because it is not valid.'.format(datetime.datetime.now()))
148149
else:

hathor/simulator/simulator.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -259,11 +259,7 @@ def _build_vertex_verifiers(
259259
"""
260260
return VertexVerifiers(
261261
block=SimulatorBlockVerifier(settings=settings, daa=daa, feature_service=feature_service),
262-
merge_mined_block=SimulatorMergeMinedBlockVerifier(
263-
settings=settings,
264-
daa=daa,
265-
feature_service=feature_service
266-
),
262+
merge_mined_block=SimulatorMergeMinedBlockVerifier(),
267263
tx=SimulatorTransactionVerifier(settings=settings, daa=daa),
268264
token_creation_tx=SimulatorTokenCreationTransactionVerifier(settings=settings, daa=daa),
269265
)

hathor/verification/block_verifier.py

-42
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from hathor.conf.settings import HathorSettings
1616
from hathor.daa import DifficultyAdjustmentAlgorithm
1717
from hathor.feature_activation.feature_service import BlockIsMissingSignal, BlockIsSignaling, FeatureService
18-
from hathor.profiler import get_cpu_profiler
1918
from hathor.transaction import BaseTransaction, Block
2019
from hathor.transaction.exceptions import (
2120
BlockMustSignalError,
@@ -28,8 +27,6 @@
2827
)
2928
from hathor.verification.vertex_verifier import VertexVerifier
3029

31-
cpu = get_cpu_profiler()
32-
3330

3431
class BlockVerifier(VertexVerifier):
3532
__slots__ = ('_feature_service', )
@@ -44,45 +41,6 @@ def __init__(
4441
super().__init__(settings=settings, daa=daa)
4542
self._feature_service = feature_service
4643

47-
def verify_basic(self, block: Block, *, skip_block_weight_verification: bool = False) -> None:
48-
"""Partially run validations, the ones that need parents/inputs are skipped."""
49-
if not skip_block_weight_verification:
50-
self.verify_weight(block)
51-
self.verify_reward(block)
52-
53-
@cpu.profiler(key=lambda _, block: 'block-verify!{}'.format(block.hash.hex()))
54-
def verify(self, block: Block) -> None:
55-
"""
56-
(1) confirms at least two pending transactions and references last block
57-
(2) solves the pow with the correct weight (done in HathorManager)
58-
(3) creates the correct amount of tokens in the output (done in HathorManager)
59-
(4) all parents must exist and have timestamp smaller than ours
60-
(5) data field must contain at most BLOCK_DATA_MAX_SIZE bytes
61-
(6) whether this block must signal feature support
62-
"""
63-
# TODO Should we validate a limit of outputs?
64-
if block.is_genesis:
65-
# TODO do genesis validation
66-
return
67-
68-
self.verify_without_storage(block)
69-
70-
# (1) and (4)
71-
self.verify_parents(block)
72-
73-
self.verify_height(block)
74-
75-
self.verify_mandatory_signaling(block)
76-
77-
def verify_without_storage(self, block: Block) -> None:
78-
""" Run all verifications that do not need a storage.
79-
"""
80-
self.verify_pow(block)
81-
self.verify_no_inputs(block)
82-
self.verify_outputs(block)
83-
self.verify_data(block)
84-
self.verify_sigops_output(block)
85-
8644
def verify_height(self, block: Block) -> None:
8745
"""Validate that the block height is enough to confirm all transactions being confirmed."""
8846
meta = block.get_metadata()

hathor/verification/merge_mined_block_verifier.py

+2-8
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,12 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
from hathor.transaction import Block, MergeMinedBlock
16-
from hathor.verification.block_verifier import BlockVerifier
15+
from hathor.transaction import MergeMinedBlock
1716

1817

19-
class MergeMinedBlockVerifier(BlockVerifier):
18+
class MergeMinedBlockVerifier:
2019
__slots__ = ()
2120

22-
def verify_without_storage(self, block: Block) -> None:
23-
assert isinstance(block, MergeMinedBlock)
24-
self.verify_aux_pow(block)
25-
super().verify_without_storage(block)
26-
2721
def verify_aux_pow(self, block: MergeMinedBlock) -> None:
2822
""" Verify auxiliary proof-of-work (for merged mining).
2923
"""

hathor/verification/verification_service.py

+59-13
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from hathor.conf.settings import HathorSettings
2020
from hathor.daa import DifficultyAdjustmentAlgorithm
2121
from hathor.feature_activation.feature_service import FeatureService
22+
from hathor.profiler import get_cpu_profiler
2223
from hathor.transaction import BaseTransaction, Block, MergeMinedBlock, Transaction, TxVersion
2324
from hathor.transaction.token_creation_tx import TokenCreationTransaction
2425
from hathor.transaction.validation_state import ValidationState
@@ -27,6 +28,8 @@
2728
from hathor.verification.token_creation_transaction_verifier import TokenCreationTransactionVerifier
2829
from hathor.verification.transaction_verifier import TransactionVerifier
2930

31+
cpu = get_cpu_profiler()
32+
3033

3134
class VertexVerifiers(NamedTuple):
3235
"""A group of verifier instances, one for each vertex type."""
@@ -49,7 +52,7 @@ def create_defaults(
4952
"""
5053
return VertexVerifiers(
5154
block=BlockVerifier(settings=settings, daa=daa, feature_service=feature_service),
52-
merge_mined_block=MergeMinedBlockVerifier(settings=settings, daa=daa, feature_service=feature_service),
55+
merge_mined_block=MergeMinedBlockVerifier(),
5356
tx=TransactionVerifier(settings=settings, daa=daa),
5457
token_creation_tx=TokenCreationTransactionVerifier(settings=settings, daa=daa),
5558
)
@@ -116,16 +119,10 @@ def verify_basic(self, vertex: BaseTransaction, *, skip_block_weight_verificatio
116119
match vertex.version:
117120
case TxVersion.REGULAR_BLOCK:
118121
assert type(vertex) is Block
119-
self.verifiers.block.verify_basic(
120-
vertex,
121-
skip_block_weight_verification=skip_block_weight_verification
122-
)
122+
self._verify_basic_block(vertex, skip_weight_verification=skip_block_weight_verification)
123123
case TxVersion.MERGE_MINED_BLOCK:
124124
assert type(vertex) is MergeMinedBlock
125-
self.verifiers.merge_mined_block.verify_basic(
126-
vertex,
127-
skip_block_weight_verification=skip_block_weight_verification
128-
)
125+
self._verify_basic_merge_mined_block(vertex, skip_weight_verification=skip_block_weight_verification)
129126
case TxVersion.REGULAR_TRANSACTION:
130127
assert type(vertex) is Transaction
131128
self.verifiers.tx.verify_basic(vertex)
@@ -135,6 +132,15 @@ def verify_basic(self, vertex: BaseTransaction, *, skip_block_weight_verificatio
135132
case _:
136133
assert_never(vertex.version)
137134

135+
def _verify_basic_block(self, block: Block, *, skip_weight_verification: bool) -> None:
136+
"""Partially run validations, the ones that need parents/inputs are skipped."""
137+
if not skip_weight_verification:
138+
self.verifiers.block.verify_weight(block)
139+
self.verifiers.block.verify_reward(block)
140+
141+
def _verify_basic_merge_mined_block(self, block: MergeMinedBlock, *, skip_weight_verification: bool) -> None:
142+
self._verify_basic_block(block, skip_weight_verification=skip_weight_verification)
143+
138144
def verify(self, vertex: BaseTransaction, *, reject_locked_reward: bool = True) -> None:
139145
"""Run all verifications. Raises on error.
140146
@@ -143,10 +149,10 @@ def verify(self, vertex: BaseTransaction, *, reject_locked_reward: bool = True)
143149
match vertex.version:
144150
case TxVersion.REGULAR_BLOCK:
145151
assert type(vertex) is Block
146-
self.verifiers.block.verify(vertex)
152+
self._verify_block(vertex)
147153
case TxVersion.MERGE_MINED_BLOCK:
148154
assert type(vertex) is MergeMinedBlock
149-
self.verifiers.merge_mined_block.verify(vertex)
155+
self._verify_merge_mined_block(vertex)
150156
case TxVersion.REGULAR_TRANSACTION:
151157
assert type(vertex) is Transaction
152158
self.verifiers.tx.verify(vertex, reject_locked_reward=reject_locked_reward)
@@ -156,15 +162,42 @@ def verify(self, vertex: BaseTransaction, *, reject_locked_reward: bool = True)
156162
case _:
157163
assert_never(vertex.version)
158164

165+
@cpu.profiler(key=lambda _, block: 'block-verify!{}'.format(block.hash.hex()))
166+
def _verify_block(self, block: Block) -> None:
167+
"""
168+
(1) confirms at least two pending transactions and references last block
169+
(2) solves the pow with the correct weight (done in HathorManager)
170+
(3) creates the correct amount of tokens in the output (done in HathorManager)
171+
(4) all parents must exist and have timestamp smaller than ours
172+
(5) data field must contain at most BLOCK_DATA_MAX_SIZE bytes
173+
(6) whether this block must signal feature support
174+
"""
175+
# TODO Should we validate a limit of outputs?
176+
if block.is_genesis:
177+
# TODO do genesis validation
178+
return
179+
180+
self.verify_without_storage(block)
181+
182+
# (1) and (4)
183+
self.verifiers.block.verify_parents(block)
184+
185+
self.verifiers.block.verify_height(block)
186+
187+
self.verifiers.block.verify_mandatory_signaling(block)
188+
189+
def _verify_merge_mined_block(self, block: MergeMinedBlock) -> None:
190+
self._verify_block(block)
191+
159192
def verify_without_storage(self, vertex: BaseTransaction) -> None:
160193
# We assert with type() instead of isinstance() because each subclass has a specific branch.
161194
match vertex.version:
162195
case TxVersion.REGULAR_BLOCK:
163196
assert type(vertex) is Block
164-
self.verifiers.block.verify_without_storage(vertex)
197+
self._verify_without_storage_block(vertex)
165198
case TxVersion.MERGE_MINED_BLOCK:
166199
assert type(vertex) is MergeMinedBlock
167-
self.verifiers.merge_mined_block.verify_without_storage(vertex)
200+
self._verify_without_storage_merge_mined_block(vertex)
168201
case TxVersion.REGULAR_TRANSACTION:
169202
assert type(vertex) is Transaction
170203
self.verifiers.tx.verify_without_storage(vertex)
@@ -173,3 +206,16 @@ def verify_without_storage(self, vertex: BaseTransaction) -> None:
173206
self.verifiers.token_creation_tx.verify_without_storage(vertex)
174207
case _:
175208
assert_never(vertex.version)
209+
210+
def _verify_without_storage_block(self, block: Block) -> None:
211+
""" Run all verifications that do not need a storage.
212+
"""
213+
self.verifiers.block.verify_pow(block)
214+
self.verifiers.block.verify_no_inputs(block)
215+
self.verifiers.block.verify_outputs(block)
216+
self.verifiers.block.verify_data(block)
217+
self.verifiers.block.verify_sigops_output(block)
218+
219+
def _verify_without_storage_merge_mined_block(self, block: MergeMinedBlock) -> None:
220+
self.verifiers.merge_mined_block.verify_aux_pow(block)
221+
self._verify_without_storage_block(block)

0 commit comments

Comments
 (0)