Skip to content
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
2 changes: 1 addition & 1 deletion hathor/transaction/resources/create_tx.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ def _verify_unsigned_skip_pow(self, tx: Transaction) -> None:
# 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)
verifiers.tx.verify_sum(tx.get_complete_token_info())


CreateTxResource.openapi = {
Expand Down
6 changes: 3 additions & 3 deletions hathor/verification/token_creation_transaction_verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,9 @@
from hathor.conf.settings import HathorSettings
from hathor.transaction.exceptions import InvalidToken, TransactionDataError
from hathor.transaction.token_creation_tx import TokenCreationTransaction
from hathor.transaction.transaction import TokenInfo
from hathor.transaction.util import clean_token_string
from hathor.types import TokenUid
from hathor.util import not_none


Expand All @@ -25,16 +27,14 @@ class TokenCreationTransactionVerifier:
def __init__(self, *, settings: HathorSettings) -> None:
self._settings = settings

def verify_minted_tokens(self, tx: TokenCreationTransaction) -> None:
def verify_minted_tokens(self, tx: TokenCreationTransaction, token_dict: dict[TokenUid, TokenInfo]) -> None:
""" Besides all checks made on regular transactions, a few extra ones are made:
- only HTR tokens on the inputs;
- new tokens are actually being minted;

:raises InvalidToken: when there's an error in token operations
:raises InputOutputMismatch: if sum of inputs is not equal to outputs and there's no mint/melt
"""
token_dict = tx.get_complete_token_info()

# make sure tokens are being minted
token_info = token_dict[not_none(tx.hash)]
if token_info.amount <= 0:
Expand Down
14 changes: 1 addition & 13 deletions hathor/verification/transaction_verifier.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,18 +141,6 @@ def verify_script(self, *, tx: Transaction, input_tx: TxInput, spent_tx: BaseTra
except ScriptError as e:
raise InvalidInputData(e) from e

def verify_sum(self, tx: Transaction) -> None:
"""Verify that the sum of outputs is equal of the sum of inputs, for each token.

If there are authority UTXOs involved, tokens can be minted or melted, so the above rule may
not be respected.

:raises InvalidToken: when there's an error in token operations
:raises InputOutputMismatch: if sum of inputs is not equal to outputs and there's no mint/melt
"""
token_dict = tx.get_complete_token_info()
self.verify_authorities_and_deposit(token_dict)

def verify_reward_locked(self, tx: Transaction) -> None:
"""Will raise `RewardLocked` if any reward is spent before the best block height is enough, considering only
the block rewards spent by this tx itself, and not the inherited `min_height`."""
Expand All @@ -179,7 +167,7 @@ def verify_output_token_indexes(self, tx: Transaction) -> None:
if output.get_token_index() > len(tx.tokens):
raise InvalidToken('token uid index not available: index {}'.format(output.get_token_index()))

def verify_authorities_and_deposit(self, token_dict: dict[TokenUid, TokenInfo]) -> None:
def verify_sum(self, token_dict: dict[TokenUid, TokenInfo]) -> None:
"""Verify that the sum of outputs is equal of the sum of inputs, for each token. If sum of inputs
and outputs is not 0, make sure inputs have mint/melt authority.

Expand Down
17 changes: 13 additions & 4 deletions hathor/verification/verification_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@
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.transaction import TokenInfo
from hathor.transaction.validation_state import ValidationState
from hathor.types import TokenUid
from hathor.verification.vertex_verifiers import VertexVerifiers

cpu = get_cpu_profiler()
Expand Down Expand Up @@ -167,7 +169,13 @@ def _verify_merge_mined_block(self, block: MergeMinedBlock) -> None:
self._verify_block(block)

@cpu.profiler(key=lambda _, tx: 'tx-verify!{}'.format(tx.hash.hex()))
def _verify_tx(self, tx: Transaction, *, reject_locked_reward: bool) -> None:
def _verify_tx(
self,
tx: Transaction,
*,
reject_locked_reward: bool,
token_dict: dict[TokenUid, TokenInfo] | None = None
) -> None:
""" Common verification for all transactions:
(i) number of inputs is at most 256
(ii) number of outputs is at most 256
Expand All @@ -186,7 +194,7 @@ def _verify_tx(self, tx: Transaction, *, reject_locked_reward: bool) -> None:
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.vertex.verify_parents(tx)
self.verifiers.tx.verify_sum(tx)
self.verifiers.tx.verify_sum(token_dict or tx.get_complete_token_info())
if reject_locked_reward:
self.verifiers.tx.verify_reward_locked(tx)

Expand All @@ -195,8 +203,9 @@ def _verify_token_creation_tx(self, tx: TokenCreationTransaction, *, reject_lock

We also overload verify_sum to make some different checks
"""
self._verify_tx(tx, reject_locked_reward=reject_locked_reward)
self.verifiers.token_creation_tx.verify_minted_tokens(tx)
token_dict = tx.get_complete_token_info()
self._verify_tx(tx, reject_locked_reward=reject_locked_reward, token_dict=token_dict)
self.verifiers.token_creation_tx.verify_minted_tokens(tx, token_dict)
self.verifiers.token_creation_tx.verify_token_info(tx)

def verify_without_storage(self, vertex: BaseTransaction) -> None:
Expand Down
2 changes: 1 addition & 1 deletion tests/tx/test_tx.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def test_input_output_match(self):
_input.data = P2PKH.create_input_data(public_bytes, signature)

with self.assertRaises(InputOutputMismatch):
self._verifiers.tx.verify_sum(tx)
self._verifiers.tx.verify_sum(tx.get_complete_token_info())

def test_validation(self):
# add 100 blocks and check that walking through get_next_block_best_chain yields the same blocks
Expand Down