|
28 | 28 |
|
29 | 29 | from hathor.checkpoint import Checkpoint
|
30 | 30 | from hathor.conf.get_settings import get_settings
|
31 |
| -from hathor.transaction.exceptions import ( |
32 |
| - DuplicatedParents, |
33 |
| - IncorrectParents, |
34 |
| - InvalidOutputScriptSize, |
35 |
| - InvalidOutputValue, |
36 |
| - InvalidToken, |
37 |
| - ParentDoesNotExist, |
38 |
| - PowError, |
39 |
| - TimestampError, |
40 |
| - TooManyOutputs, |
41 |
| - TooManySigOps, |
42 |
| - WeightError, |
43 |
| -) |
| 31 | +from hathor.transaction.exceptions import InvalidOutputValue, WeightError |
44 | 32 | from hathor.transaction.transaction_metadata import TransactionMetadata
|
45 | 33 | from hathor.transaction.util import VerboseCallback, int_to_bytes, unpack, unpack_len
|
46 | 34 | from hathor.transaction.validation_state import ValidationState
|
|
70 | 58 | # Weight (d), timestamp (I), and parents len (B)
|
71 | 59 | _GRAPH_FORMAT_STRING = '!dIB'
|
72 | 60 |
|
73 |
| -# tx should have 2 parents, both other transactions |
74 |
| -_TX_PARENTS_TXS = 2 |
75 |
| -_TX_PARENTS_BLOCKS = 0 |
76 |
| - |
77 |
| -# blocks have 3 parents, 2 txs and 1 block |
78 |
| -_BLOCK_PARENTS_TXS = 2 |
79 |
| -_BLOCK_PARENTS_BLOCKS = 1 |
80 |
| - |
81 | 61 | # The int value of one byte
|
82 | 62 | _ONE_BYTE = 0xFF
|
83 | 63 |
|
@@ -540,137 +520,6 @@ def verify_checkpoint(self, checkpoints: list[Checkpoint]) -> None:
|
540 | 520 | To be implemented by tx/block, used by `self.validate_checkpoint`. Should not modify the validation state."""
|
541 | 521 | raise NotImplementedError
|
542 | 522 |
|
543 |
| - def verify_parents(self) -> None: |
544 |
| - """All parents must exist and their timestamps must be smaller than ours. |
545 |
| -
|
546 |
| - Also, txs should have 2 other txs as parents, while blocks should have 2 txs + 1 block. |
547 |
| -
|
548 |
| - Parents must be ordered with blocks first, followed by transactions. |
549 |
| -
|
550 |
| - :raises TimestampError: when our timestamp is less or equal than our parent's timestamp |
551 |
| - :raises ParentDoesNotExist: when at least one of our parents does not exist |
552 |
| - :raises IncorrectParents: when tx does not confirm the correct number/type of parent txs |
553 |
| - """ |
554 |
| - from hathor.transaction.storage.exceptions import TransactionDoesNotExist |
555 |
| - |
556 |
| - assert self.storage is not None |
557 |
| - |
558 |
| - # check if parents are duplicated |
559 |
| - parents_set = set(self.parents) |
560 |
| - if len(self.parents) > len(parents_set): |
561 |
| - raise DuplicatedParents('Tx has duplicated parents: {}', [tx_hash.hex() for tx_hash in self.parents]) |
562 |
| - |
563 |
| - my_parents_txs = 0 # number of tx parents |
564 |
| - my_parents_blocks = 0 # number of block parents |
565 |
| - min_timestamp: Optional[int] = None |
566 |
| - |
567 |
| - for parent_hash in self.parents: |
568 |
| - try: |
569 |
| - parent = self.storage.get_transaction(parent_hash) |
570 |
| - assert parent.hash is not None |
571 |
| - if self.timestamp <= parent.timestamp: |
572 |
| - raise TimestampError('tx={} timestamp={}, parent={} timestamp={}'.format( |
573 |
| - self.hash_hex, |
574 |
| - self.timestamp, |
575 |
| - parent.hash_hex, |
576 |
| - parent.timestamp, |
577 |
| - )) |
578 |
| - |
579 |
| - if parent.is_block: |
580 |
| - if self.is_block and not parent.is_genesis: |
581 |
| - if self.timestamp - parent.timestamp > self._settings.MAX_DISTANCE_BETWEEN_BLOCKS: |
582 |
| - raise TimestampError('Distance between blocks is too big' |
583 |
| - ' ({} seconds)'.format(self.timestamp - parent.timestamp)) |
584 |
| - if my_parents_txs > 0: |
585 |
| - raise IncorrectParents('Parents which are blocks must come before transactions') |
586 |
| - for pi_hash in parent.parents: |
587 |
| - pi = self.storage.get_transaction(parent_hash) |
588 |
| - if not pi.is_block: |
589 |
| - min_timestamp = ( |
590 |
| - min(min_timestamp, pi.timestamp) if min_timestamp is not None |
591 |
| - else pi.timestamp |
592 |
| - ) |
593 |
| - my_parents_blocks += 1 |
594 |
| - else: |
595 |
| - if min_timestamp and parent.timestamp < min_timestamp: |
596 |
| - raise TimestampError('tx={} timestamp={}, parent={} timestamp={}, min_timestamp={}'.format( |
597 |
| - self.hash_hex, |
598 |
| - self.timestamp, |
599 |
| - parent.hash_hex, |
600 |
| - parent.timestamp, |
601 |
| - min_timestamp |
602 |
| - )) |
603 |
| - my_parents_txs += 1 |
604 |
| - except TransactionDoesNotExist: |
605 |
| - raise ParentDoesNotExist('tx={} parent={}'.format(self.hash_hex, parent_hash.hex())) |
606 |
| - |
607 |
| - # check for correct number of parents |
608 |
| - if self.is_block: |
609 |
| - parents_txs = _BLOCK_PARENTS_TXS |
610 |
| - parents_blocks = _BLOCK_PARENTS_BLOCKS |
611 |
| - else: |
612 |
| - parents_txs = _TX_PARENTS_TXS |
613 |
| - parents_blocks = _TX_PARENTS_BLOCKS |
614 |
| - if my_parents_blocks != parents_blocks: |
615 |
| - raise IncorrectParents('wrong number of parents (block type): {}, expecting {}'.format( |
616 |
| - my_parents_blocks, parents_blocks)) |
617 |
| - if my_parents_txs != parents_txs: |
618 |
| - raise IncorrectParents('wrong number of parents (tx type): {}, expecting {}'.format( |
619 |
| - my_parents_txs, parents_txs)) |
620 |
| - |
621 |
| - def verify_pow(self, override_weight: Optional[float] = None) -> None: |
622 |
| - """Verify proof-of-work |
623 |
| -
|
624 |
| - :raises PowError: when the hash is equal or greater than the target |
625 |
| - """ |
626 |
| - assert self.hash is not None |
627 |
| - numeric_hash = int(self.hash_hex, self.HEX_BASE) |
628 |
| - minimum_target = self.get_target(override_weight) |
629 |
| - if numeric_hash >= minimum_target: |
630 |
| - raise PowError(f'Transaction has invalid data ({numeric_hash} < {minimum_target})') |
631 |
| - |
632 |
| - def verify_number_of_outputs(self) -> None: |
633 |
| - """Verify number of outputs does not exceeds the limit""" |
634 |
| - if len(self.outputs) > self._settings.MAX_NUM_OUTPUTS: |
635 |
| - raise TooManyOutputs('Maximum number of outputs exceeded') |
636 |
| - |
637 |
| - def verify_sigops_output(self) -> None: |
638 |
| - """ Count sig operations on all outputs and verify that the total sum is below the limit |
639 |
| - """ |
640 |
| - from hathor.transaction.scripts import get_sigops_count |
641 |
| - n_txops = 0 |
642 |
| - |
643 |
| - for tx_output in self.outputs: |
644 |
| - n_txops += get_sigops_count(tx_output.script) |
645 |
| - |
646 |
| - if n_txops > self._settings.MAX_TX_SIGOPS_OUTPUT: |
647 |
| - raise TooManySigOps('TX[{}]: Maximum number of sigops for all outputs exceeded ({})'.format( |
648 |
| - self.hash_hex, n_txops)) |
649 |
| - |
650 |
| - def verify_outputs(self) -> None: |
651 |
| - """Verify there are no hathor authority UTXOs and outputs are all positive |
652 |
| -
|
653 |
| - :raises InvalidToken: when there's a hathor authority utxo |
654 |
| - :raises InvalidOutputValue: output has negative value |
655 |
| - :raises TooManyOutputs: when there are too many outputs |
656 |
| - """ |
657 |
| - self.verify_number_of_outputs() |
658 |
| - for index, output in enumerate(self.outputs): |
659 |
| - # no hathor authority UTXO |
660 |
| - if (output.get_token_index() == 0) and output.is_token_authority(): |
661 |
| - raise InvalidToken('Cannot have authority UTXO for hathor tokens: {}'.format( |
662 |
| - output.to_human_readable())) |
663 |
| - |
664 |
| - # output value must be positive |
665 |
| - if output.value <= 0: |
666 |
| - raise InvalidOutputValue('Output value must be a positive integer. Value: {} and index: {}'.format( |
667 |
| - output.value, index)) |
668 |
| - |
669 |
| - if len(output.script) > self._settings.MAX_OUTPUT_SCRIPT_SIZE: |
670 |
| - raise InvalidOutputScriptSize('size: {} and max-size: {}'.format( |
671 |
| - len(output.script), self._settings.MAX_OUTPUT_SCRIPT_SIZE |
672 |
| - )) |
673 |
| - |
674 | 523 | def resolve(self, update_time: bool = False) -> bool:
|
675 | 524 | """Run a CPU mining looking for the nonce that solves the proof-of-work
|
676 | 525 |
|
|
0 commit comments