Skip to content
Closed
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
18 changes: 16 additions & 2 deletions hathor/builder/builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
TransactionStorage,
)
from hathor.util import Random, Reactor, get_environment_info
from hathor.verification.verification_service import VerificationService
from hathor.verification.verification_service import VerificationService, VertexVerifiers
from hathor.wallet import BaseWallet, Wallet

logger = get_logger()
Expand Down Expand Up @@ -102,6 +102,7 @@ def __init__(self) -> None:
self._feature_service: Optional[FeatureService] = None
self._bit_signaling_service: Optional[BitSignalingService] = None

self._vertex_verifiers: Optional[VertexVerifiers] = None
self._verification_service: Optional[VerificationService] = None

self._rocksdb_path: Optional[str] = None
Expand Down Expand Up @@ -432,10 +433,18 @@ def _get_or_create_bit_signaling_service(self, tx_storage: TransactionStorage) -

def _get_or_create_verification_service(self) -> VerificationService:
if self._verification_service is None:
self._verification_service = VerificationService()
verifiers = self._get_or_create_vertex_verifiers()
self._verification_service = VerificationService(verifiers=verifiers)

return self._verification_service

def _get_or_create_vertex_verifiers(self) -> VertexVerifiers:
if self._vertex_verifiers is None:
settings = self._get_or_create_settings()
self._vertex_verifiers = VertexVerifiers.create(settings=settings)

return self._vertex_verifiers

def use_memory(self) -> 'Builder':
self.check_if_can_modify()
self._storage_type = StorageType.MEMORY
Expand Down Expand Up @@ -533,6 +542,11 @@ def set_verification_service(self, verification_service: VerificationService) ->
self._verification_service = verification_service
return self

def set_vertex_verifiers(self, vertex_verifiers: VertexVerifiers) -> 'Builder':
self.check_if_can_modify()
self._vertex_verifiers = vertex_verifiers
return self

def set_reactor(self, reactor: Reactor) -> 'Builder':
self.check_if_can_modify()
self._reactor = reactor
Expand Down
5 changes: 3 additions & 2 deletions hathor/builder/cli_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
from hathor.pubsub import PubSubManager
from hathor.stratum import StratumFactory
from hathor.util import Random, Reactor
from hathor.verification.verification_service import VerificationService
from hathor.verification.verification_service import VerificationService, VertexVerifiers
from hathor.wallet import BaseWallet, HDWallet, Wallet

logger = get_logger()
Expand Down Expand Up @@ -202,7 +202,8 @@ def create_manager(self, reactor: Reactor) -> HathorManager:
not_support_features=self._args.signal_not_support
)

verification_service = VerificationService()
vertex_verifiers = VertexVerifiers.create(settings=settings)
verification_service = VerificationService(verifiers=vertex_verifiers)

p2p_manager = ConnectionsManager(
reactor,
Expand Down
7 changes: 6 additions & 1 deletion hathor/cli/mining.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@

import requests

from hathor.conf.get_settings import get_settings
from hathor.verification.block_verifier import BlockVerifier

_SLEEP_ON_ERROR_SECONDS = 5
_MAX_CONN_RETRIES = math.inf

Expand Down Expand Up @@ -134,7 +137,9 @@ def execute(args: Namespace) -> None:
block.nonce, block.weight))

try:
block.verify_without_storage()
settings = get_settings()
verifier = BlockVerifier(settings=settings)
verifier.verify_without_storage(block)
except HathorError:
print('[{}] ERROR: Block has not been pushed because it is not valid.'.format(datetime.datetime.now()))
else:
Expand Down
5 changes: 3 additions & 2 deletions hathor/stratum/stratum.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
from hathor.transaction import BaseTransaction, BitcoinAuxPow, Block, MergeMinedBlock, Transaction, sum_weights
from hathor.transaction.exceptions import PowError, ScriptError, TxValidationError
from hathor.util import Reactor, json_dumpb, json_loadb, reactor
from hathor.verification.vertex_verifier import VertexVerifier
from hathor.wallet.exceptions import InvalidAddress

if TYPE_CHECKING:
Expand Down Expand Up @@ -526,7 +527,7 @@ def handle_submit(self, params: dict, msgid: Optional[str]) -> None:
self.log.debug('share received', block=tx, block_base=block_base.hex(), block_base_hash=block_base_hash.hex())

try:
tx.verify_pow(job.weight)
VertexVerifier.verify_pow(tx, override_weight=job.weight)
except PowError:
self.log.error('bad share, discard', job_weight=job.weight, tx=tx)
return self.send_error(INVALID_SOLUTION, msgid, {
Expand All @@ -542,7 +543,7 @@ def handle_submit(self, params: dict, msgid: Optional[str]) -> None:
self.manager.reactor.callLater(0, self.job_request)

try:
tx.verify_pow()
VertexVerifier.verify_pow(tx)
except PowError:
# Transaction pow was not enough, but the share was succesfully submited
self.log.info('high hash, keep mining', tx=tx)
Expand Down
2 changes: 1 addition & 1 deletion hathor/transaction/resources/create_tx.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def render_POST(self, request):
# conservative estimate of the input data size to estimate a valid weight
tx_input.data = b'\0' * 107
tx.weight = minimum_tx_weight(fake_signed_tx)
tx.verify_unsigned_skip_pow()
self.manager.verification_service.verifiers.tx.verify_unsigned_skip_pow(tx)

if tx.is_double_spending():
raise InvalidNewTransaction('At least one of your inputs has already been spent.')
Expand Down
47 changes: 0 additions & 47 deletions hathor/verification/block_verification.py

This file was deleted.

79 changes: 79 additions & 0 deletions hathor/verification/block_verifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# Copyright 2023 Hathor Labs
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from hathor.profiler import get_cpu_profiler
from hathor.transaction import BaseTransaction, Block
from hathor.verification.vertex_verifier import VertexVerifier

cpu = get_cpu_profiler()


class BlockVerifier(VertexVerifier):
__slots__ = ()

def verify_basic(self, block: Block, *, skip_block_weight_verification: bool = False) -> None:
"""Partially run validations, the ones that need parents/inputs are skipped."""
if not skip_block_weight_verification:
self.verify_weight(block)
self.verify_reward(block)

@cpu.profiler(key=lambda _, block: 'block-verify!{}'.format(block.hash.hex()))
def verify(self, block: Block) -> None:
"""
(1) confirms at least two pending transactions and references last block
(2) solves the pow with the correct weight (done in HathorManager)
(3) creates the correct amount of tokens in the output (done in HathorManager)
(4) all parents must exist and have timestamp smaller than ours
(5) data field must contain at most BLOCK_DATA_MAX_SIZE bytes
"""
# TODO Should we validate a limit of outputs?
if block.is_genesis:
# TODO do genesis validation
return

self.verify_without_storage(block)

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

self.verify_height(block)

def verify_without_storage(self, block: Block) -> None:
""" Run all verifications that do not need a storage.
"""
block.verify_without_storage()

@staticmethod
def verify_height(block: Block) -> None:
"""Validate that the block height is enough to confirm all transactions being confirmed."""
block.verify_height()

def verify_weight(self, block: Block) -> None:
"""Validate minimum block difficulty."""
block.verify_weight()

@staticmethod
def verify_reward(block: Block) -> None:
"""Validate reward amount."""
block.verify_reward()

@staticmethod
def verify_no_inputs(block: Block) -> None:
block.verify_no_inputs()

def verify_outputs(self, block: BaseTransaction) -> None:
block.verify_outputs()

def verify_data(self, block: Block) -> None:
block.verify_data()
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from hathor.transaction.token_creation_tx import TokenCreationTransaction
from hathor.verification import transaction_verification
from hathor.transaction import MergeMinedBlock
from hathor.verification.block_verifier import BlockVerifier


def verify(tx: TokenCreationTransaction, *, reject_locked_reward: bool = True) -> None:
""" Run all validations as regular transactions plus validation on token info.
class MergeMinedBlockVerifier(BlockVerifier):
__slots__ = ()

We also overload verify_sum to make some different checks
"""
transaction_verification.verify(tx, reject_locked_reward=reject_locked_reward)
tx.verify_token_info()
@staticmethod
def verify_aux_pow(block: MergeMinedBlock) -> None:
""" Verify auxiliary proof-of-work (for merged mining).
"""
block.verify_aux_pow()
33 changes: 33 additions & 0 deletions hathor/verification/token_creation_transaction_verifier.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright 2023 Hathor Labs
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from hathor.transaction.token_creation_tx import TokenCreationTransaction
from hathor.verification.transaction_verifier import TransactionVerifier


class TokenCreationTransactionVerifier(TransactionVerifier):
__slots__ = ()

def verify(self, tx: TokenCreationTransaction, *, reject_locked_reward: bool = True) -> None:
""" Run all validations as regular transactions plus validation on token info.

We also overload verify_sum to make some different checks
"""
super().verify(tx, reject_locked_reward=reject_locked_reward)
self.verify_token_info(tx)

def verify_token_info(self, tx: TokenCreationTransaction) -> None:
""" Validates token info
"""
tx.verify_token_info()
53 changes: 0 additions & 53 deletions hathor/verification/transaction_verification.py

This file was deleted.

Loading