Skip to content
Open
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
5 changes: 1 addition & 4 deletions hathor/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.


class HathorError(Exception):
"""Base class for exceptions in Hathor."""
pass
from hathorlib.exceptions import HathorError # noqa: F401


class BuilderError(Exception):
Expand Down
92 changes: 7 additions & 85 deletions hathor/nanocontracts/blueprint_syntax_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,88 +12,10 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import annotations

import inspect
from typing import Callable

from hathor.nanocontracts.exception import BlueprintSyntaxError


def validate_has_self_arg(fn: Callable, annotation_name: str) -> None:
"""Validate the `self` arg of a callable."""
arg_spec = inspect.getfullargspec(fn)
if len(arg_spec.args) == 0:
raise BlueprintSyntaxError(f'@{annotation_name} method must have `self` argument: `{fn.__name__}()`')

if arg_spec.args[0] != 'self':
raise BlueprintSyntaxError(
f'@{annotation_name} method first argument must be called `self`: `{fn.__name__}()`'
)

if 'self' in arg_spec.annotations.keys():
raise BlueprintSyntaxError(f'@{annotation_name} method `self` argument must not be typed: `{fn.__name__}()`')


def validate_method_types(fn: Callable) -> None:
"""Validate the arg and return types of a callable."""
special_args = ['self']
arg_spec = inspect.getfullargspec(fn)

if 'return' not in arg_spec.annotations:
raise BlueprintSyntaxError(f'missing return type on method `{fn.__name__}`')

# TODO: This currently fails for types such as unions, probably because this is the wrong
# parsing function to use. Fix this.
# from hathor.nanocontracts.fields import get_field_class_for_attr
# return_type = arg_spec.annotations['return']
# if return_type is not None:
# try:
# get_field_class_for_attr(return_type)
# except UnknownFieldType:
# raise BlueprintSyntaxError(
# f'unsupported return type `{return_type}` on method `{fn.__name__}`'
# )

for arg_name in arg_spec.args:
if arg_name in special_args:
continue

if arg_name not in arg_spec.annotations:
raise BlueprintSyntaxError(f'argument `{arg_name}` on method `{fn.__name__}` must be typed')

# TODO: This currently fails for @view methods with NamedTuple as args for example,
# because API calls use a different parsing function. Fix this.
# arg_type = arg_spec.annotations[arg_name]
# try:
# get_field_class_for_attr(arg_type)
# except UnknownFieldType:
# raise BlueprintSyntaxError(
# f'unsupported type `{arg_type.__name__}` on argument `{arg_name}` of method `{fn.__name__}`'
# )


def validate_has_ctx_arg(fn: Callable, annotation_name: str) -> None:
"""Validate the context arg of a callable."""
arg_spec = inspect.getfullargspec(fn)

if len(arg_spec.args) < 2:
raise BlueprintSyntaxError(
f'@{annotation_name} method must have `Context` argument: `{fn.__name__}()`'
)

from hathor.nanocontracts import Context
second_arg = arg_spec.args[1]
if arg_spec.annotations[second_arg] is not Context:
raise BlueprintSyntaxError(
f'@{annotation_name} method second arg `{second_arg}` argument must be of type `Context`: '
f'`{fn.__name__}()`'
)


def validate_has_not_ctx_arg(fn: Callable, annotation_name: str) -> None:
"""Validate that a callable doesn't have a `Context` arg."""
from hathor.nanocontracts import Context
arg_spec = inspect.getfullargspec(fn)
if Context in arg_spec.annotations.values():
raise BlueprintSyntaxError(f'@{annotation_name} method cannot have arg with type `Context`: `{fn.__name__}()`')
# Re-export from hathorlib for backward compatibility
from hathorlib.nanocontracts.blueprint_syntax_validation import ( # noqa: F401
validate_has_ctx_arg,
validate_has_not_ctx_arg,
validate_has_self_arg,
validate_method_types,
)
225 changes: 42 additions & 183 deletions hathor/nanocontracts/exception.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,49 @@
# See the License for the specific language governing permissions and
# limitations under the License.

from hathor.exception import HathorError
from hathor.transaction.exceptions import TxValidationError

"""
All exceptions in this module MUST inherit from NCFail so they're
correctly caught by the block consensus to fail NC transactions.
"""


class NCFail(HathorError):
"""Raised by Blueprint's methods to fail execution."""


class BlueprintSyntaxError(SyntaxError, NCFail):
"""Raised when a blueprint contains invalid syntax."""
pass
# Re-export all exceptions from hathorlib for backward compatibility
from hathorlib.nanocontracts.exception import ( # noqa: F401
BlueprintDoesNotExist,
BlueprintSyntaxError,
NanoContractDoesNotExist,
NCAlreadyInitializedContractError,
NCAttributeError,
NCContractCreationAtMempool,
NCContractCreationNotFound,
NCContractCreationVoided,
NCDisabledBuiltinError,
NCFail,
NCForbiddenAction,
NCForbiddenReentrancy,
NCInsufficientFunds,
NCInvalidAction,
NCInvalidContext,
NCInvalidContractId,
NCInvalidFee,
NCInvalidFeePaymentToken,
NCInvalidInitializeMethodCall,
NCInvalidPublicMethodCallFromView,
NCInvalidSyscall,
NCNumberOfCallsExceeded,
NCRecursionError,
NCSerializationArgTooLong,
NCSerializationError,
NCSerializationTypeError,
NCTokenAlreadyExists,
NCTypeError,
NCUninitializedContractError,
NCViewMethodError,
OCBBlueprintNotConfirmed,
OCBInvalidBlueprintVertexType,
OCBInvalidScript,
OCBOutOfFuelDuringLoading,
OCBOutOfMemoryDuringLoading,
OCBPubKeyNotAllowed,
UnknownFieldType,
)

# hathor-specific exceptions that depend on TxValidationError


class NCTxValidationError(TxValidationError, NCFail):
Expand All @@ -46,178 +73,10 @@ class NCInvalidSeqnum(NCTxValidationError, NCFail):
pass


class NanoContractDoesNotExist(NCFail):
pass


class BlueprintDoesNotExist(NCFail):
pass


class NCSerializationError(NCFail):
pass


class NCSerializationArgTooLong(NCSerializationError):
pass


class NCSerializationTypeError(NCSerializationError):
pass


class NCViewMethodError(NCFail):
"""Raised when a view method changes the state of the contract."""
pass


class NCMethodNotFound(NCTxValidationError):
"""Raised when a method is not found in a nano contract."""
pass


class NCInsufficientFunds(NCFail):
"""Raised when there is not enough funds to withdrawal from a nano contract."""
pass


class NCAttributeError(NCFail):
pass


class NCInvalidContext(NCFail):
"""Raised when trying to run a method with an invalid context."""
pass


class NCRecursionError(NCFail):
"""Raised when recursion gets too deep."""


class NCNumberOfCallsExceeded(NCFail):
"""Raised when the total number of calls have been exceeded."""


class NCInvalidContractId(NCFail):
"""Raised when a contract call is invalid."""


class NCInvalidMethodCall(NCTxValidationError):
"""Raised when a contract calls another contract's invalid method."""


class NCInvalidFeePaymentToken(NCFail):
"""Raised when a payment token is invalid."""


class NCInvalidInitializeMethodCall(NCFail):
"""Raised when a contract calls another contract's initialize method."""


class NCInvalidPublicMethodCallFromView(NCFail):
"""Raised when a contract calls another contract's initialize method."""


class NCAlreadyInitializedContractError(NCFail):
"""Raised when one tries to initialize a contract that has already been initialized."""


class NCUninitializedContractError(NCFail):
"""Raised when a contract calls a method from an uninitialized contract."""


class NCInvalidAction(NCFail):
"""Raised when an action is invalid."""
pass


class NCInvalidFee(NCFail):
"""Raised when a fee is invalid."""
pass


class NCInvalidSyscall(NCFail):
"""Raised when a syscall is invalid."""
pass


class NCTokenAlreadyExists(NCFail):
"""Raised when one tries to create a duplicated token."""


class NCForbiddenAction(NCFail):
"""Raised when an action is forbidden on a method."""
pass


class NCForbiddenReentrancy(NCFail):
"""Raised when a reentrancy is forbidden on a method."""
pass


class NCTypeError(NCFail):
"""Raised when a wrong type is used."""
pass


class UnknownFieldType(NCFail):
"""Raised when there is no field available for a given type."""
pass


class NCContractCreationNotFound(NCFail):
"""Raised when a nano contract creation transaction is not found.

This error might also happen when the transaction is at the mempool or when it fails execution."""
pass


class NCContractCreationAtMempool(NCContractCreationNotFound):
"""Raised when a nano contract creation transaction is at the mempool, so it has not been
executed yet."""
pass


class NCContractCreationVoided(NCContractCreationNotFound):
"""Raised when a nano contract creation transaction is voided.

The two most common reasons to have a voided transaction is because it was voided by
another transaction (e.g., double spending) or it has failed execution."""
pass


class OCBInvalidScript(NCFail):
"""Raised when an On-Chain Blueprint script does not pass our script restrictions check.
"""
pass


class OCBInvalidBlueprintVertexType(NCFail):
"""Raised when a vertex that is not an OnChainBlueprint is used as a blueprint-id.
"""
pass


class OCBBlueprintNotConfirmed(NCFail):
"""Raised when trying to use an OnChainBlueprint that is not confirmed by a block in the current best chain.
"""


class OCBPubKeyNotAllowed(NCFail):
"""Raised when an OnChainBlueprint transaction uses a pubkey that is not explicitly allowed in the settings.
"""


class OCBOutOfFuelDuringLoading(NCFail):
"""Raised when loading an On-chain Blueprint and the execution exceeds the fuel limit.
"""


class OCBOutOfMemoryDuringLoading(NCFail):
"""Raised when loading an On-chain Blueprint and the execution exceeds the memory limit.
"""


class NCDisabledBuiltinError(NCFail):
"""Raised when a disabled builtin is used during creation or execution of a nanocontract.
"""
Loading