Skip to content

Commit

Permalink
refactor(verification): remove VertexVerifier inheritance
Browse files Browse the repository at this point in the history
  • Loading branch information
glevco committed Nov 27, 2023
1 parent 11ad5b6 commit da25588
Show file tree
Hide file tree
Showing 13 changed files with 385 additions and 251 deletions.
3 changes: 2 additions & 1 deletion hathor/builder/cli_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
from hathor.pubsub import PubSubManager
from hathor.stratum import StratumFactory
from hathor.util import Random, Reactor, not_none
from hathor.verification.verification_service import VerificationService, VertexVerifiers
from hathor.verification.verification_service import VerificationService
from hathor.verification.vertex_verifiers import VertexVerifiers
from hathor.wallet import BaseWallet, HDWallet, Wallet

logger = get_logger()
Expand Down
33 changes: 4 additions & 29 deletions hathor/simulator/patches.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,41 +18,16 @@

from hathor.mining.cpu_mining_service import CpuMiningService
from hathor.transaction import BaseTransaction
from hathor.verification.block_verifier import BlockVerifier
from hathor.verification.merge_mined_block_verifier import MergeMinedBlockVerifier
from hathor.verification.token_creation_transaction_verifier import TokenCreationTransactionVerifier
from hathor.verification.transaction_verifier import TransactionVerifier
from hathor.verification.vertex_verifier import VertexVerifier

logger = get_logger()


def _verify_pow(vertex: BaseTransaction) -> None:
assert vertex.hash is not None
logger.new().debug('Skipping VertexVerifier.verify_pow() for simulator')


class SimulatorBlockVerifier(BlockVerifier):
@classmethod
def verify_pow(cls, vertex: BaseTransaction, *, override_weight: Optional[float] = None) -> None:
_verify_pow(vertex)


class SimulatorMergeMinedBlockVerifier(MergeMinedBlockVerifier):
@classmethod
def verify_pow(cls, vertex: BaseTransaction, *, override_weight: Optional[float] = None) -> None:
_verify_pow(vertex)


class SimulatorTransactionVerifier(TransactionVerifier):
@classmethod
def verify_pow(cls, vertex: BaseTransaction, *, override_weight: Optional[float] = None) -> None:
_verify_pow(vertex)


class SimulatorTokenCreationTransactionVerifier(TokenCreationTransactionVerifier):
class SimulatorVertexVerifier(VertexVerifier):
@classmethod
def verify_pow(cls, vertex: BaseTransaction, *, override_weight: Optional[float] = None) -> None:
_verify_pow(vertex)
assert vertex.hash is not None
logger.new().debug('Skipping VertexVerifier.verify_pow() for simulator')


class SimulatorCpuMiningService(CpuMiningService):
Expand Down
20 changes: 7 additions & 13 deletions hathor/simulator/simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,10 @@
from hathor.p2p.peer_id import PeerId
from hathor.simulator.clock import HeapClock, MemoryReactorHeapClock
from hathor.simulator.miner.geometric_miner import GeometricMiner
from hathor.simulator.patches import (
SimulatorBlockVerifier,
SimulatorCpuMiningService,
SimulatorMergeMinedBlockVerifier,
SimulatorTokenCreationTransactionVerifier,
SimulatorTransactionVerifier,
)
from hathor.simulator.patches import SimulatorCpuMiningService, SimulatorVertexVerifier
from hathor.simulator.tx_generator import RandomTransactionGenerator
from hathor.util import Random
from hathor.verification.verification_service import VertexVerifiers
from hathor.verification.vertex_verifiers import VertexVerifiers
from hathor.wallet import HDWallet

if TYPE_CHECKING:
Expand Down Expand Up @@ -257,9 +251,9 @@ def _build_vertex_verifiers(
"""
A custom VertexVerifiers builder to be used by the simulator.
"""
return VertexVerifiers(
block=SimulatorBlockVerifier(settings=settings, daa=daa, feature_service=feature_service),
merge_mined_block=SimulatorMergeMinedBlockVerifier(),
tx=SimulatorTransactionVerifier(settings=settings, daa=daa),
token_creation_tx=SimulatorTokenCreationTransactionVerifier(settings=settings),
return VertexVerifiers.create(
settings=settings,
vertex_verifier=SimulatorVertexVerifier(settings=settings, daa=daa),
daa=daa,
feature_service=feature_service,
)
22 changes: 12 additions & 10 deletions hathor/transaction/resources/create_tx.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from hathor.cli.openapi_files.register import register_resource
from hathor.crypto.util import decode_address
from hathor.exception import InvalidNewTransaction
from hathor.manager import HathorManager
from hathor.transaction import Transaction, TxInput, TxOutput
from hathor.transaction.scripts import create_output_script
from hathor.util import api_catch_exceptions, json_dumpb, json_loadb
Expand Down Expand Up @@ -49,7 +50,7 @@ class CreateTxResource(Resource):
"""
isLeaf = True

def __init__(self, manager):
def __init__(self, manager: HathorManager) -> None:
# Important to have the manager so we can know the tx_storage
self.manager = manager

Expand Down Expand Up @@ -107,15 +108,16 @@ def render_POST(self, request):
def _verify_unsigned_skip_pow(self, tx: Transaction) -> None:
""" Same as .verify but skipping pow and signature verification."""
assert type(tx) is Transaction
verifier = self.manager.verification_service.verifiers.tx
verifier.verify_number_of_inputs(tx)
verifier.verify_number_of_outputs(tx)
verifier.verify_outputs(tx)
verifier.verify_sigops_output(tx)
verifier.verify_sigops_input(tx)
verifier.verify_inputs(tx, skip_script=True) # need to run verify_inputs first to check if all inputs exist
verifier.verify_parents(tx)
verifier.verify_sum(tx)
verifiers = self.manager.verification_service.verifiers
verifiers.tx.verify_number_of_inputs(tx)
verifiers.vertex.verify_number_of_outputs(tx)
verifiers.tx.verify_outputs(tx)
verifiers.vertex.verify_sigops_output(tx)
verifiers.tx.verify_sigops_input(tx)
# need to run verify_inputs first to check if all inputs exist
verifiers.tx.verify_inputs(tx, skip_script=True)
verifiers.vertex.verify_parents(tx)
verifiers.tx.verify_sum(tx)


CreateTxResource.openapi = {
Expand Down
16 changes: 9 additions & 7 deletions hathor/verification/block_verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from hathor.conf.settings import HathorSettings
from hathor.daa import DifficultyAdjustmentAlgorithm
from hathor.feature_activation.feature_service import BlockIsMissingSignal, BlockIsSignaling, FeatureService
from hathor.transaction import BaseTransaction, Block
from hathor.transaction import Block
from hathor.transaction.exceptions import (
BlockMustSignalError,
BlockWithInputs,
Expand All @@ -28,17 +28,20 @@
from hathor.verification.vertex_verifier import VertexVerifier


class BlockVerifier(VertexVerifier):
__slots__ = ('_feature_service', )
class BlockVerifier:
__slots__ = ('_settings', '_vertex_verifier', '_daa', '_feature_service')

def __init__(
self,
*,
settings: HathorSettings,
vertex_verifier: VertexVerifier,
daa: DifficultyAdjustmentAlgorithm,
feature_service: FeatureService | None = None
) -> None:
super().__init__(settings=settings, daa=daa)
self._settings = settings
self._vertex_verifier = vertex_verifier
self._daa = daa
self._feature_service = feature_service

def verify_height(self, block: Block) -> None:
Expand Down Expand Up @@ -71,9 +74,8 @@ def verify_no_inputs(self, block: Block) -> None:
if inputs:
raise BlockWithInputs('number of inputs {}'.format(len(inputs)))

def verify_outputs(self, block: BaseTransaction) -> None:
assert isinstance(block, Block)
super().verify_outputs(block)
def verify_outputs(self, block: Block) -> None:
self._vertex_verifier.verify_outputs(block)
for output in block.outputs:
if output.get_token_index() > 0:
raise BlockWithTokensError('in output: {}'.format(output.to_human_readable()))
Expand Down
22 changes: 17 additions & 5 deletions hathor/verification/transaction_verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from hathor.conf.settings import HathorSettings
from hathor.daa import DifficultyAdjustmentAlgorithm
from hathor.profiler import get_cpu_profiler
from hathor.transaction import BaseTransaction, Transaction, TxInput
from hathor.transaction.exceptions import (
Expand Down Expand Up @@ -39,8 +41,19 @@
cpu = get_cpu_profiler()


class TransactionVerifier(VertexVerifier):
__slots__ = ()
class TransactionVerifier:
__slots__ = ('_settings', '_vertex_verifier', '_daa')

def __init__(
self,
*,
settings: HathorSettings,
vertex_verifier: VertexVerifier,
daa: DifficultyAdjustmentAlgorithm,
) -> None:
self._settings = settings
self._vertex_verifier = vertex_verifier
self._daa = daa

def verify_parents_basic(self, tx: Transaction) -> None:
"""Verify number and non-duplicity of parents."""
Expand Down Expand Up @@ -164,13 +177,12 @@ def verify_number_of_inputs(self, tx: Transaction) -> None:
if not tx.is_genesis:
raise NoInputError('Transaction must have at least one input')

def verify_outputs(self, tx: BaseTransaction) -> None:
def verify_outputs(self, tx: Transaction) -> None:
"""Verify outputs reference an existing token uid in the tokens list
:raises InvalidToken: output references non existent token uid
"""
assert isinstance(tx, Transaction)
super().verify_outputs(tx)
self._vertex_verifier.verify_outputs(tx)
for output in tx.outputs:
# check index is valid
if output.get_token_index() > len(tx.tokens):
Expand Down
49 changes: 7 additions & 42 deletions hathor/verification/verification_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,52 +12,17 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from typing import NamedTuple

from typing_extensions import assert_never

from hathor.conf.settings import HathorSettings
from hathor.daa import DifficultyAdjustmentAlgorithm
from hathor.feature_activation.feature_service import FeatureService
from hathor.profiler import get_cpu_profiler
from hathor.transaction import BaseTransaction, Block, MergeMinedBlock, Transaction, TxVersion
from hathor.transaction.token_creation_tx import TokenCreationTransaction
from hathor.transaction.validation_state import ValidationState
from hathor.verification.block_verifier import BlockVerifier
from hathor.verification.merge_mined_block_verifier import MergeMinedBlockVerifier
from hathor.verification.token_creation_transaction_verifier import TokenCreationTransactionVerifier
from hathor.verification.transaction_verifier import TransactionVerifier
from hathor.verification.vertex_verifiers import VertexVerifiers

cpu = get_cpu_profiler()


class VertexVerifiers(NamedTuple):
"""A group of verifier instances, one for each vertex type."""
block: BlockVerifier
merge_mined_block: MergeMinedBlockVerifier
tx: TransactionVerifier
token_creation_tx: TokenCreationTransactionVerifier

@classmethod
def create_defaults(
cls,
*,
settings: HathorSettings,
daa: DifficultyAdjustmentAlgorithm,
feature_service: FeatureService | None = None,
) -> 'VertexVerifiers':
"""
Create a VertexVerifiers instance using the default verifier for each vertex type,
from all required dependencies.
"""
return VertexVerifiers(
block=BlockVerifier(settings=settings, daa=daa, feature_service=feature_service),
merge_mined_block=MergeMinedBlockVerifier(),
tx=TransactionVerifier(settings=settings, daa=daa),
token_creation_tx=TokenCreationTransactionVerifier(settings=settings),
)


class VerificationService:
__slots__ = ('verifiers', )

Expand Down Expand Up @@ -192,7 +157,7 @@ def _verify_block(self, block: Block) -> None:
self.verify_without_storage(block)

# (1) and (4)
self.verifiers.block.verify_parents(block)
self.verifiers.vertex.verify_parents(block)

self.verifiers.block.verify_height(block)

Expand Down Expand Up @@ -220,7 +185,7 @@ def _verify_tx(self, tx: Transaction, *, reject_locked_reward: bool) -> None:
self.verify_without_storage(tx)
self.verifiers.tx.verify_sigops_input(tx)
self.verifiers.tx.verify_inputs(tx) # need to run verify_inputs first to check if all inputs exist
self.verifiers.tx.verify_parents(tx)
self.verifiers.vertex.verify_parents(tx)
self.verifiers.tx.verify_sum(tx)
if reject_locked_reward:
self.verifiers.tx.verify_reward_locked(tx)
Expand Down Expand Up @@ -255,11 +220,11 @@ def verify_without_storage(self, vertex: BaseTransaction) -> None:
def _verify_without_storage_block(self, block: Block) -> None:
""" Run all verifications that do not need a storage.
"""
self.verifiers.block.verify_pow(block)
self.verifiers.vertex.verify_pow(block)
self.verifiers.block.verify_no_inputs(block)
self.verifiers.block.verify_outputs(block)
self.verifiers.block.verify_data(block)
self.verifiers.block.verify_sigops_output(block)
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)
Expand All @@ -268,10 +233,10 @@ def _verify_without_storage_merge_mined_block(self, block: MergeMinedBlock) -> N
def _verify_without_storage_tx(self, tx: Transaction) -> None:
""" Run all verifications that do not need a storage.
"""
self.verifiers.tx.verify_pow(tx)
self.verifiers.vertex.verify_pow(tx)
self.verifiers.tx.verify_number_of_inputs(tx)
self.verifiers.tx.verify_outputs(tx)
self.verifiers.tx.verify_sigops_output(tx)
self.verifiers.vertex.verify_sigops_output(tx)

def _verify_without_storage_token_creation_tx(self, tx: TokenCreationTransaction) -> None:
self._verify_without_storage_tx(tx)
Loading

0 comments on commit da25588

Please sign in to comment.