From 3c134eec5a25b5733cade6b50ee5437f4550fc4b Mon Sep 17 00:00:00 2001 From: "Juan M. Tirado" Date: Mon, 27 May 2024 11:41:21 +0200 Subject: [PATCH] [PAN-1924] Clean repo for OS (#6) * fix: prepare for OS --- .bandit | 19 +- .../pull_request_template.md | 0 .github/workflows/ci.yaml | 12 + .github/workflows/sonar.yaml | 10 + .gitmodules | 3 - .mypy.ini | 6 + .style.yapf | 10 +- README.md | 9 +- pantos/__init__.py | 0 pantos/common | 1 - pantos/servicenode/__main__.py | 5 +- pantos/servicenode/blockchains/avalanche.py | 1 - pantos/servicenode/blockchains/base.py | 20 +- pantos/servicenode/blockchains/bnbchain.py | 1 - pantos/servicenode/blockchains/celo.py | 1 - pantos/servicenode/blockchains/cronos.py | 1 - pantos/servicenode/blockchains/ethereum.py | 10 +- pantos/servicenode/blockchains/fantom.py | 1 - pantos/servicenode/blockchains/polygon.py | 1 - pantos/servicenode/blockchains/solana.py | 1 - pantos/servicenode/business/bids.py | 1 - pantos/servicenode/business/node.py | 1 - pantos/servicenode/business/plugins.py | 1 - pantos/servicenode/business/transfers.py | 94 +++--- pantos/servicenode/celery.py | 25 +- pantos/servicenode/configuration.py | 6 +- pantos/servicenode/database/__init__.py | 6 +- pantos/servicenode/database/access.py | 47 ++- pantos/servicenode/database/exceptions.py | 7 +- pantos/servicenode/database/migrations/env.py | 6 +- .../5e552e0ec844_remove_id_from_bids_table.py | 6 +- ...982c1f3b95_create_deferrable_constraint.py | 19 +- .../versions/bd913c5bfdfb_off_chain_bids.py | 40 +-- .../c4c46d14ca6a_initial_database_schema.py | 25 +- pantos/servicenode/database/models.py | 48 +-- pantos/servicenode/plugins/base.py | 1 - pantos/servicenode/plugins/bids.py | 1 - pantos/servicenode/restapi.py | 69 ++--- requirements.txt | 14 - service-node-config.yml | 222 ++++++++++++++ setup.py | 30 -- sonar-project.properties | 5 + submodules/common | 1 - tests/blockchains/test_base.py | 27 +- tests/blockchains/test_ethereum.py | 279 ++++++------------ tests/business/test_bids.py | 9 +- tests/business/test_node.py | 2 - tests/business/test_plugins.py | 1 - tests/business/test_transfers.py | 16 +- tests/database/conftest.py | 10 +- tests/database/sqlite/access/conftest.py | 31 +- tests/restapi/test_bids.py | 3 +- tests/restapi/test_transfer.py | 16 +- tests/restapi/test_transfer_status.py | 6 +- tests/test_application.py | 3 +- 55 files changed, 586 insertions(+), 604 deletions(-) mode change 120000 => 100644 .bandit rename .github/{PULL_REQUEST_TEMPLATE => }/pull_request_template.md (100%) create mode 100644 .github/workflows/ci.yaml create mode 100644 .github/workflows/sonar.yaml delete mode 100644 .gitmodules create mode 100644 .mypy.ini mode change 120000 => 100644 .style.yapf delete mode 100644 pantos/__init__.py delete mode 120000 pantos/common delete mode 100644 requirements.txt create mode 100644 service-node-config.yml delete mode 100644 setup.py create mode 100644 sonar-project.properties delete mode 160000 submodules/common diff --git a/.bandit b/.bandit deleted file mode 120000 index 4f679d9..0000000 --- a/.bandit +++ /dev/null @@ -1 +0,0 @@ -submodules/common/.bandit \ No newline at end of file diff --git a/.bandit b/.bandit new file mode 100644 index 0000000..affd098 --- /dev/null +++ b/.bandit @@ -0,0 +1,18 @@ +tests: + - B103 + - B108 + - B306 + - B307 + - B313 + - B314 + - B315 + - B316 + - B317 + - B318 + - B319 + - B320 + - B601 + - B602 + - B604 + - B608 + - B609 diff --git a/.github/PULL_REQUEST_TEMPLATE/pull_request_template.md b/.github/pull_request_template.md similarity index 100% rename from .github/PULL_REQUEST_TEMPLATE/pull_request_template.md rename to .github/pull_request_template.md diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml new file mode 100644 index 0000000..b6bd1af --- /dev/null +++ b/.github/workflows/ci.yaml @@ -0,0 +1,12 @@ +name: CI + +on: + push: + branches: + - main + pull_request: + +jobs: + shared: + uses: pantos-io/ci-workflows/.github/workflows/python-ci.yml@8651148b739f73851ab50c671da422c94bc55095 + secrets: inherit diff --git a/.github/workflows/sonar.yaml b/.github/workflows/sonar.yaml new file mode 100644 index 0000000..8e56322 --- /dev/null +++ b/.github/workflows/sonar.yaml @@ -0,0 +1,10 @@ +name: Sonar + +on: + workflow_run: + workflows: [CI] + types: [completed] + +jobs: + shared: + uses: pantos-io/ci-workflows/.github/workflows/sonar.yml@v1 diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index c304186..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "submodules/common"] - path = submodules/common - url = https://github.com/pantos-io/common.git diff --git a/.mypy.ini b/.mypy.ini new file mode 100644 index 0000000..55c2a6c --- /dev/null +++ b/.mypy.ini @@ -0,0 +1,6 @@ +[mypy] +namespace_packages = True +explicit_package_bases = True + +[mypy-pantos.common.*] +ignore_missing_imports = True diff --git a/.style.yapf b/.style.yapf deleted file mode 120000 index 94791b4..0000000 --- a/.style.yapf +++ /dev/null @@ -1 +0,0 @@ -submodules/common/.style.yapf \ No newline at end of file diff --git a/.style.yapf b/.style.yapf new file mode 100644 index 0000000..1fe2bd6 --- /dev/null +++ b/.style.yapf @@ -0,0 +1,9 @@ +[style] +based_on_style = pep8 +spaces_before_comment = 2 +split_before_logical_operator = true +column_limit = 79 +allow_split_before_dict_value = false +blank_lines_between_top_level_imports_and_variables = 1 +blank_line_before_nested_class_or_def = false +split_before_named_assigns = false diff --git a/README.md b/README.md index 5136814..4cff558 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,10 @@ +Pantos logo + +[![CI](https://github.com/pantos-io/servicenode/actions/workflows/ci.yaml/badge.svg?branch=main)](https://github.com/pantos-io/servicenode/actions/workflows/ci.yaml) +[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=pantos-io_servicenode&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=pantos-io_servicenode) + + + # Pantos Service Node (reference implementation) ## 1. Introduction @@ -159,4 +166,4 @@ sudo rabbitmqctl set_permissions -p pantos-service-node pantos-service-node ".*" ## 4. Contributing -At the moment, contributing to this project is not available. \ No newline at end of file +For contributions take a look at our [code of conduct](CODE_OF_CONDUCT.md). \ No newline at end of file diff --git a/pantos/__init__.py b/pantos/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/pantos/common b/pantos/common deleted file mode 120000 index d909363..0000000 --- a/pantos/common +++ /dev/null @@ -1 +0,0 @@ -../submodules/common/pantos/common \ No newline at end of file diff --git a/pantos/servicenode/__main__.py b/pantos/servicenode/__main__.py index 92624d8..402c85f 100644 --- a/pantos/servicenode/__main__.py +++ b/pantos/servicenode/__main__.py @@ -14,8 +14,5 @@ ssl_context = (None if ssl_certificate is None or ssl_private_key is None else (ssl_certificate, ssl_private_key)) debug = config['application']['debug'] - application.run(host=host, - port=port, - ssl_context=ssl_context, - debug=debug, + application.run(host=host, port=port, ssl_context=ssl_context, debug=debug, use_reloader=False) diff --git a/pantos/servicenode/blockchains/avalanche.py b/pantos/servicenode/blockchains/avalanche.py index b78c887..1274fb6 100644 --- a/pantos/servicenode/blockchains/avalanche.py +++ b/pantos/servicenode/blockchains/avalanche.py @@ -21,7 +21,6 @@ class AvalancheClient(EthereumClient): """Avalanche-specific blockchain client. """ - @classmethod def get_blockchain(cls) -> Blockchain: # Docstring inherited diff --git a/pantos/servicenode/blockchains/base.py b/pantos/servicenode/blockchains/base.py index cf2f949..1f4ad38 100644 --- a/pantos/servicenode/blockchains/base.py +++ b/pantos/servicenode/blockchains/base.py @@ -38,7 +38,6 @@ class InsufficientBalanceError(BlockchainClientError): insufficient balance. """ - def __init__(self, **kwargs: typing.Any): # Docstring inherited super().__init__('insufficient balance', **kwargs) @@ -49,7 +48,6 @@ class InvalidSignatureError(BlockchainClientError): invalid signature. """ - def __init__(self, **kwargs: typing.Any): # Docstring inherited super().__init__('invalid signature', **kwargs) @@ -61,7 +59,6 @@ class UnresolvableTransferSubmissionError(BlockchainClientError): submission. """ - def __init__(self, **kwargs: typing.Any): # Docstring inherited super().__init__('unresolvable transfer/transferFrom submission error', @@ -72,7 +69,6 @@ class BlockchainClient(BlockchainHandler, ErrorCreator[BlockchainClientError]): """Base class for all blockchain clients. """ - def __init__(self): """Construct a blockchain client instance. @@ -95,10 +91,8 @@ def __init__(self): try: initialize_blockchain_utilities( self.get_blockchain(), [blockchain_node_url], - fallback_blockchain_nodes_urls, - average_block_time, - required_transaction_confirmations, - transaction_network_id, + fallback_blockchain_nodes_urls, average_block_time, + required_transaction_confirmations, transaction_network_id, default_private_key=(private_key, private_key_password), celery_tasks_enabled=True) except BlockchainUtilitiesError: @@ -417,9 +411,10 @@ def get_transfer_submission_status( except BlockchainUtilitiesError: raise self._create_unresolvable_transfer_submission_error( internal_transaction_id=internal_transaction_id) - _logger.info('transfer/transferFrom transaction submission status', - extra=vars(status_response) - | {'internal_transaction_id': internal_transaction_id}) + _logger.info( + 'transfer/transferFrom transaction submission status', + extra=vars(status_response) + | {'internal_transaction_id': internal_transaction_id}) if not status_response.transaction_submission_completed: return BlockchainClient.TransferSubmissionStatusResponse(False) transaction_status = status_response.transaction_status @@ -433,8 +428,7 @@ def get_transfer_submission_status( self._read_on_chain_transfer_id( transaction_id, destination_blockchain)) return BlockchainClient.TransferSubmissionStatusResponse( - True, - transaction_status=transaction_status, + True, transaction_status=transaction_status, transaction_id=transaction_id, on_chain_transfer_id=on_chain_transfer_id) diff --git a/pantos/servicenode/blockchains/bnbchain.py b/pantos/servicenode/blockchains/bnbchain.py index 4a21948..dd20b2d 100644 --- a/pantos/servicenode/blockchains/bnbchain.py +++ b/pantos/servicenode/blockchains/bnbchain.py @@ -21,7 +21,6 @@ class BnbChainClient(EthereumClient): """BNB-Chain-specific blockchain client. """ - @classmethod def get_blockchain(cls) -> Blockchain: # Docstring inherited diff --git a/pantos/servicenode/blockchains/celo.py b/pantos/servicenode/blockchains/celo.py index cbfdae4..56817e9 100644 --- a/pantos/servicenode/blockchains/celo.py +++ b/pantos/servicenode/blockchains/celo.py @@ -21,7 +21,6 @@ class CeloClient(EthereumClient): """Celo-specific blockchain client. """ - @classmethod def get_blockchain(cls) -> Blockchain: # Docstring inherited diff --git a/pantos/servicenode/blockchains/cronos.py b/pantos/servicenode/blockchains/cronos.py index da9aa0f..cb771ee 100644 --- a/pantos/servicenode/blockchains/cronos.py +++ b/pantos/servicenode/blockchains/cronos.py @@ -21,7 +21,6 @@ class CronosClient(EthereumClient): """Cronos-specific blockchain client. """ - @classmethod def get_blockchain(cls) -> Blockchain: # Docstring inherited diff --git a/pantos/servicenode/blockchains/ethereum.py b/pantos/servicenode/blockchains/ethereum.py index f860bdd..ec09638 100644 --- a/pantos/servicenode/blockchains/ethereum.py +++ b/pantos/servicenode/blockchains/ethereum.py @@ -62,7 +62,6 @@ class EthereumClient(BlockchainClient): """Ethereum-specific blockchain client. """ - def __init__(self): # Docstring inherited super().__init__() @@ -159,8 +158,7 @@ def register_node(self, node_url: str, node_stake: int, _logger.info('node registration submitted', extra=extra_info) except Exception: raise self._create_error('unable to register the service node', - node_url=node_url, - node_stake=node_stake) + node_url=node_url, node_stake=node_stake) def start_transfer_submission( self, request: BlockchainClient.TransferSubmissionStartRequest) \ @@ -318,8 +316,7 @@ def _read_on_chain_transfer_id(self, transaction_id: str, assert ( transaction_receipt['transactionHash'].hex() == transaction_id) _logger.info( - 'transfer/transferFrom transaction receipt', - extra=json.loads( + 'transfer/transferFrom transaction receipt', extra=json.loads( web3.Web3.to_json(transaction_receipt))) # type: ignore hub_contract = self._create_hub_contract(node_connections) if self.get_blockchain() is destination_blockchain: @@ -334,8 +331,7 @@ def _read_on_chain_transfer_id(self, transaction_id: str, except Exception: raise self._create_error( 'unable to read the Pantos transfer ID on the source ' - 'blockchain', - transaction_id=transaction_id, + 'blockchain', transaction_id=transaction_id, destination_blockchain=destination_blockchain) def __create_node_connections(self) -> NodeConnections: diff --git a/pantos/servicenode/blockchains/fantom.py b/pantos/servicenode/blockchains/fantom.py index 2714a8e..fc58e55 100644 --- a/pantos/servicenode/blockchains/fantom.py +++ b/pantos/servicenode/blockchains/fantom.py @@ -21,7 +21,6 @@ class FantomClient(EthereumClient): """Fantom-specific blockchain client. """ - @classmethod def get_blockchain(cls) -> Blockchain: # Docstring inherited diff --git a/pantos/servicenode/blockchains/polygon.py b/pantos/servicenode/blockchains/polygon.py index 2360535..f74c201 100644 --- a/pantos/servicenode/blockchains/polygon.py +++ b/pantos/servicenode/blockchains/polygon.py @@ -21,7 +21,6 @@ class PolygonClient(EthereumClient): """Polygon-specific blockchain client. """ - @classmethod def get_blockchain(cls) -> Blockchain: # Docstring inherited diff --git a/pantos/servicenode/blockchains/solana.py b/pantos/servicenode/blockchains/solana.py index d06d9a3..d06cc39 100644 --- a/pantos/servicenode/blockchains/solana.py +++ b/pantos/servicenode/blockchains/solana.py @@ -21,7 +21,6 @@ class SolanaClient(BlockchainClient): """Solana-specific blockchain client. """ - def __init__(self): # Docstring inherited pass # pragma: no cover diff --git a/pantos/servicenode/business/bids.py b/pantos/servicenode/business/bids.py index efa97fa..f6a6239 100644 --- a/pantos/servicenode/business/bids.py +++ b/pantos/servicenode/business/bids.py @@ -28,7 +28,6 @@ class BidInteractor(Interactor): """Interactor for managing service node bids. """ - @dataclasses.dataclass class Bid: """Data for a transfer bid. diff --git a/pantos/servicenode/business/node.py b/pantos/servicenode/business/node.py index 1027ce2..81b31d1 100644 --- a/pantos/servicenode/business/node.py +++ b/pantos/servicenode/business/node.py @@ -26,7 +26,6 @@ class NodeInteractor(Interactor): """Interactor for managing the service node itself. """ - def update_node_registrations(self) -> None: """Update the service node registrations on all supported blockchains. diff --git a/pantos/servicenode/business/plugins.py b/pantos/servicenode/business/plugins.py index cbf128f..9a68f44 100644 --- a/pantos/servicenode/business/plugins.py +++ b/pantos/servicenode/business/plugins.py @@ -31,7 +31,6 @@ class BidPluginInteractor(Interactor): """Interactor for handling the bid plugin operations. """ - def replace_bids(self, source_blockchain: Blockchain) -> int: """Replace the old bids with new bids given by the bid plugin. Additionally, the Validator fee is added to the bid fee. diff --git a/pantos/servicenode/business/transfers.py b/pantos/servicenode/business/transfers.py index 9b74ba1..bcb23c4 100644 --- a/pantos/servicenode/business/transfers.py +++ b/pantos/servicenode/business/transfers.py @@ -69,7 +69,6 @@ class TransferInteractor(Interactor): """Interactor for handling token transfers. """ - @dataclasses.dataclass class ConfirmTransferRequest: """Request data for confirming the inclusion of a token transfer @@ -126,8 +125,7 @@ def confirm_transfer(self, request: ConfirmTransferRequest) -> bool: request.internal_transaction_id, request.destination_blockchain) except UnresolvableTransferSubmissionError: - _logger.error('token transfer failed', - extra=extra_info, + _logger.error('token transfer failed', extra=extra_info, exc_info=True) database_access.reset_transfer_nonce( request.internal_transfer_id) @@ -262,8 +260,7 @@ def __single_chain_transfer(self, request.internal_transfer_id, TransferStatus.FAILED) raise TransferInteractorUnrecoverableError( 'source and destination token addresses must be equal for ' - 'a single-chain token transfer', - request=request) + 'a single-chain token transfer', request=request) transfer_request = BlockchainClient.TransferSubmissionStartRequest( request.internal_transfer_id, request.sender_address, request.recipient_address, request.source_token_address, @@ -352,17 +349,14 @@ def __check_valid_until(self, source_blockchain: Blockchain, raise TransferInteractorBidNotAcceptedError( message='"valid until" timestamp must be at least ' 'the current timestamp plus the service ' - 'node bid\'s execution time', - field_name='valid_until') + 'node bid\'s execution time', field_name='valid_until') except TransferInteractorBidNotAcceptedError: _logger.critical('unable to check the "valid until" timestamp', exc_info=True) raise def __is_valid_execution_time_limit( - self, - blockchain: Blockchain, - execution_time_limit: int, + self, blockchain: Blockchain, execution_time_limit: int, bid_execution_time: int, start_time: typing.Optional[float] = None) -> bool: """Check if a given execution time limit matches the execution @@ -443,19 +437,17 @@ def __check_valid_bid(self, bid: ServiceNodeBid, source_blockchain_id: int, 'Checking if given bid is for source/destination blockchain') if (bid.source_blockchain != source_blockchain_id or bid.destination_blockchain != destination_blockchain_id): - _logger.info('new transfer request: invalid bid', - extra={ - 'bid.fee': bid.fee, - 'bid.valid_until': bid.valid_until, - 'bid.execution_time': bid.execution_time, - 'bid.source_blockchain': bid.source_blockchain, - 'bid.destination_blockchain': - bid.destination_blockchain, - 'source_blockchain_id': source_blockchain_id, - 'destination_blockchain_id': - destination_blockchain_id, - 'bid.signature': bid.signature - }) + _logger.info( + 'new transfer request: invalid bid', extra={ + 'bid.fee': bid.fee, + 'bid.valid_until': bid.valid_until, + 'bid.execution_time': bid.execution_time, + 'bid.source_blockchain': bid.source_blockchain, + 'bid.destination_blockchain': bid.destination_blockchain, + 'source_blockchain_id': source_blockchain_id, + 'destination_blockchain_id': destination_blockchain_id, + 'bid.signature': bid.signature + }) raise TransferInteractorBidNotAcceptedError( message='bid not valid for blockchain pair', field_name='bid.source_blockchain/bid.destination_blockchain') @@ -465,16 +457,15 @@ def __check_valid_bid(self, bid: ServiceNodeBid, source_blockchain_id: int, bid_expired = self.__has_bid_expired(bid.valid_until) if bid_expired: - _logger.info('new transfer request: bid expired', - extra={ - 'bid.fee': bid.fee, - 'bid.valid_until': bid.valid_until, - 'bid.execution_time': bid.execution_time, - 'bid.source_blockchain': bid.source_blockchain, - 'bid.destination_blockchain': - bid.destination_blockchain, - 'bid.signature': bid.signature - }) + _logger.info( + 'new transfer request: bid expired', extra={ + 'bid.fee': bid.fee, + 'bid.valid_until': bid.valid_until, + 'bid.execution_time': bid.execution_time, + 'bid.source_blockchain': bid.source_blockchain, + 'bid.destination_blockchain': bid.destination_blockchain, + 'bid.signature': bid.signature + }) raise TransferInteractorBidNotAcceptedError( message='bid has expired', field_name='bid.valid_until') @@ -485,16 +476,15 @@ def __check_valid_bid(self, bid: ServiceNodeBid, source_blockchain_id: int, destination_blockchain_id, bid.signature) if not valid_bid: - _logger.info('new transfer request: invalid bid', - extra={ - 'bid.fee': bid.fee, - 'bid.valid_until': bid.valid_until, - 'bid.execution_time': bid.execution_time, - 'source_blockchain_id': source_blockchain_id, - 'destination_blockchain_id': - destination_blockchain_id, - 'bid.signature': bid.signature - }) + _logger.info( + 'new transfer request: invalid bid', extra={ + 'bid.fee': bid.fee, + 'bid.valid_until': bid.valid_until, + 'bid.execution_time': bid.execution_time, + 'source_blockchain_id': source_blockchain_id, + 'destination_blockchain_id': destination_blockchain_id, + 'bid.signature': bid.signature + }) raise TransferInteractorBidNotAcceptedError( message='bid\'s signature is invalid', field_name='bid.signature') @@ -825,8 +815,7 @@ def confirm_transfer_task(self, internal_transfer_id: int, confirm_transfer_request) except Exception as error: _logger.error('unable to confirm a token transfer', - extra=vars(confirm_transfer_request), - exc_info=True) + extra=vars(confirm_transfer_request), exc_info=True) retry_interval = config['tasks']['confirm_transfer'][ 'retry_interval_after_error'] raise self.retry(countdown=retry_interval, exc=error) @@ -899,22 +888,19 @@ def execute_transfer_task(self, internal_transfer_id: int, execute_transfer_request) confirm_transfer_interval = config['tasks']['confirm_transfer'][ 'interval'] - confirm_transfer_task.apply_async(args=(internal_transfer_id, - source_blockchain_id, - destination_blockchain_id, - str(internal_transaction_id)), - countdown=confirm_transfer_interval) + confirm_transfer_task.apply_async( + args=(internal_transfer_id, source_blockchain_id, + destination_blockchain_id, str(internal_transaction_id)), + countdown=confirm_transfer_interval) return True except TransferInteractorUnrecoverableError as error: _logger.error( 'unable to execute a token transfer - unrecoverable error', - extra=error.details, - exc_info=True) + extra=error.details, exc_info=True) return False except TransferInteractorError as error: _logger.error('unable to execute a token transfer - retrying', - extra=error.details, - exc_info=True) + extra=error.details, exc_info=True) retry_interval = config['tasks']['execute_transfer'][ 'retry_interval_after_error'] raise self.retry(countdown=retry_interval, exc=error) diff --git a/pantos/servicenode/celery.py b/pantos/servicenode/celery.py index 3c10fa1..1f7ada0 100644 --- a/pantos/servicenode/celery.py +++ b/pantos/servicenode/celery.py @@ -26,22 +26,19 @@ def is_celery_worker_process() -> bool: if is_celery_worker_process(): initialize_application(False) # pragma: no cover -celery_app = celery.Celery('pantos.servicenode', - broker=config['celery']['broker'], - backend=config['celery']['backend'], - include=[ - 'pantos.common.blockchains.tasks', - 'pantos.servicenode.business.transfers', - 'pantos.servicenode.business.plugins' - ]) +celery_app = celery.Celery( + 'pantos.servicenode', broker=config['celery']['broker'], + backend=config['celery']['backend'], include=[ + 'pantos.common.blockchains.tasks', + 'pantos.servicenode.business.transfers', + 'pantos.servicenode.business.plugins' + ]) """Celery application instance.""" # Additional Celery configuration celery_app.conf.update( - result_expires=None, - task_default_exchange='pantos.servicenode', - task_default_queue='transfers', - task_routes={ + result_expires=None, task_default_exchange='pantos.servicenode', + task_default_queue='transfers', task_routes={ 'pantos.servicenode.business.plugins.execute_bid_plugin': { 'queue': _BIDS_QUEUE_NAME }, @@ -51,9 +48,7 @@ def is_celery_worker_process() -> bool: 'pantos.common.blockchains.tasks.*': { 'queue': _TRANSFERS_QUEUE_NAME } - }, - task_track_started=True, - worker_enable_remote_control=False) + }, task_track_started=True, worker_enable_remote_control=False) if is_celery_worker_process(): # pragma: no cover # purge the bids queue at startup diff --git a/pantos/servicenode/configuration.py b/pantos/servicenode/configuration.py index 63e95dd..f81c259 100644 --- a/pantos/servicenode/configuration.py +++ b/pantos/servicenode/configuration.py @@ -291,10 +291,8 @@ } }, 'blockchains': { - 'type': - 'dict', - 'schema': - dict( + 'type': 'dict', + 'schema': dict( zip([b.name.lower() for b in Blockchain], itertools.repeat(_VALIDATION_SCHEMA_BLOCKCHAIN))) } diff --git a/pantos/servicenode/database/__init__.py b/pantos/servicenode/database/__init__.py index 8e35022..1875250 100644 --- a/pantos/servicenode/database/__init__.py +++ b/pantos/servicenode/database/__init__.py @@ -76,10 +76,8 @@ def initialize_package(is_flask_app: bool = False) -> None: config['database']['url']) sql_engine = sqlalchemy.create_engine( - config['database']['url'], - pool_size=config['database']['pool_size'], - max_overflow=config['database']['max_overflow'], - pool_pre_ping=True, + config['database']['url'], pool_size=config['database']['pool_size'], + max_overflow=config['database']['max_overflow'], pool_pre_ping=True, echo=config['database']['echo']) global _session_maker _session_maker = sqlalchemy.orm.sessionmaker(bind=sql_engine) diff --git a/pantos/servicenode/database/access.py b/pantos/servicenode/database/access.py index 4bbf3b6..817778a 100644 --- a/pantos/servicenode/database/access.py +++ b/pantos/servicenode/database/access.py @@ -57,9 +57,7 @@ def create_bid(source_blockchain: Blockchain, assert fee > 0 bid = Bid(source_blockchain_id=source_blockchain.value, destination_blockchain_id=destination_blockchain.value, - execution_time=execution_time, - valid_until=valid_until, - fee=fee) + execution_time=execution_time, valid_until=valid_until, fee=fee) with get_session_maker().begin() as session: session.add(bid) session.flush() @@ -147,17 +145,15 @@ def create_transfer(source_blockchain: Blockchain, # Create the source and destination token contract instances if # they do not exist yet source_token_contract = _read_token_contract( - session, - blockchain_id=source_blockchain.value, + session, blockchain_id=source_blockchain.value, address=source_token_address) source_token_contract_id = ( - source_token_contract.id - if source_token_contract is not None else - _create_token_contract(blockchain_id=source_blockchain.value, - address=source_token_address)) + source_token_contract.id if source_token_contract is not None + else _create_token_contract( + blockchain_id=source_blockchain.value, + address=source_token_address)) destination_token_contract = _read_token_contract( - session, - blockchain_id=destination_blockchain.value, + session, blockchain_id=destination_blockchain.value, address=destination_token_address) destination_token_contract_id = ( destination_token_contract.id if destination_token_contract @@ -167,16 +163,14 @@ def create_transfer(source_blockchain: Blockchain, # Create the hub and forwarder contract instances if they do not # exist yet hub_contract = _read_hub_contract( - session, - blockchain_id=source_blockchain.value, + session, blockchain_id=source_blockchain.value, address=hub_address) hub_contract_id = (hub_contract.id if hub_contract is not None else _create_hub_contract( blockchain_id=source_blockchain.value, address=hub_address)) forwarder_contract = _read_forwarder_contract( - session, - blockchain_id=source_blockchain.value, + session, blockchain_id=source_blockchain.value, address=forwarder_address) forwarder_contract_id = (forwarder_contract.id if forwarder_contract is not None else @@ -191,11 +185,8 @@ def create_transfer(source_blockchain: Blockchain, recipient_address=recipient_address, source_token_contract_id=source_token_contract_id, destination_token_contract_id=destination_token_contract_id, - amount=amount, - fee=fee, - sender_nonce=sender_nonce, - signature=signature, - hub_contract_id=hub_contract_id, + amount=amount, fee=fee, sender_nonce=sender_nonce, + signature=signature, hub_contract_id=hub_contract_id, forwarder_contract_id=forwarder_contract_id, status_id=TransferStatus.ACCEPTED.value) session.add(transfer) @@ -363,18 +354,16 @@ def update_transfer_nonce(internal_transfer_id: int, blockchain: Blockchain, sqlalchemy.and_( Transfer.source_blockchain_id == blockchain.value, Transfer.nonce == minimum_failed_nonce_cte.c.min))).values({ - Transfer.nonce: - sqlalchemy.case((count_failed_nonces_subquery == 0, - sqlalchemy.case( - (maximum_transfer_nonce_subquery + Transfer.nonce: sqlalchemy.case( + (count_failed_nonces_subquery == 0, + sqlalchemy.case((maximum_transfer_nonce_subquery >= latest_blockchain_nonce, maximum_transfer_nonce_subquery + 1), else_=latest_blockchain_nonce)), - (Transfer.id == internal_transfer_id, - minimum_failed_nonce_cte.c.min), - else_=sqlalchemy.null()), - Transfer.status_id: - sqlalchemy.case( + (Transfer.id == internal_transfer_id, + minimum_failed_nonce_cte.c.min), + else_=sqlalchemy.null()), + Transfer.status_id: sqlalchemy.case( (Transfer.id == internal_transfer_id, TransferStatus.ACCEPTED_NEW_NONCE_ASSIGNED.value), else_=sqlalchemy.case( diff --git a/pantos/servicenode/database/exceptions.py b/pantos/servicenode/database/exceptions.py index 9e1a93b..dd78e41 100644 --- a/pantos/servicenode/database/exceptions.py +++ b/pantos/servicenode/database/exceptions.py @@ -21,7 +21,6 @@ class SenderNonceNotUniqueError(DatabaseError): address. """ - def __init__(self, blockchain: Blockchain, sender_address: str, sender_nonce: int, **kwargs: typing.Any): """Construct an error instance. @@ -38,8 +37,6 @@ def __init__(self, blockchain: Blockchain, sender_address: str, Additional information about the error as keyword arguments. """ - super().__init__('sender nonce not unique', - blockchain=blockchain, + super().__init__('sender nonce not unique', blockchain=blockchain, sender_address=sender_address, - sender_nonce=sender_nonce, - **kwargs) + sender_nonce=sender_nonce, **kwargs) diff --git a/pantos/servicenode/database/migrations/env.py b/pantos/servicenode/database/migrations/env.py index f262fad..0116433 100644 --- a/pantos/servicenode/database/migrations/env.py +++ b/pantos/servicenode/database/migrations/env.py @@ -47,10 +47,8 @@ def run_migrations_online() -> None: alembic_config.config_ini_section)) if alembic_config.get_section( alembic_config.config_ini_section) is not None else {} connectable = sqlalchemy.engine_from_config( - alembic_ini_config, - url=config['database']['url'], - prefix="sqlalchemy.", - poolclass=sqlalchemy.pool.NullPool) + alembic_ini_config, url=config['database']['url'], + prefix="sqlalchemy.", poolclass=sqlalchemy.pool.NullPool) with connectable.connect() as connection: alembic.context.configure(connection=connection, diff --git a/pantos/servicenode/database/migrations/versions/5e552e0ec844_remove_id_from_bids_table.py b/pantos/servicenode/database/migrations/versions/5e552e0ec844_remove_id_from_bids_table.py index 9c066bd..8660d67 100644 --- a/pantos/servicenode/database/migrations/versions/5e552e0ec844_remove_id_from_bids_table.py +++ b/pantos/servicenode/database/migrations/versions/5e552e0ec844_remove_id_from_bids_table.py @@ -25,9 +25,7 @@ def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### op.add_column( 'bids', - sa.Column('id', - sa.INTEGER(), + sa.Column('id', sa.INTEGER(), server_default=sa.text("nextval('bids_id_seq'::regclass)"), - autoincrement=True, - nullable=False)) + autoincrement=True, nullable=False)) # ### end Alembic commands ### diff --git a/pantos/servicenode/database/migrations/versions/85982c1f3b95_create_deferrable_constraint.py b/pantos/servicenode/database/migrations/versions/85982c1f3b95_create_deferrable_constraint.py index 9f5bfc6..cb2262a 100644 --- a/pantos/servicenode/database/migrations/versions/85982c1f3b95_create_deferrable_constraint.py +++ b/pantos/servicenode/database/migrations/versions/85982c1f3b95_create_deferrable_constraint.py @@ -20,28 +20,23 @@ def upgrade() -> None: alembic.op.drop_index('ux_transfers_source_blockchain_id_nonce_status_id', table_name='transfers') alembic.op.create_index( - 'ix_transfers_source_blockchain_id_nonce_status_id', - 'transfers', + 'ix_transfers_source_blockchain_id_nonce_status_id', 'transfers', ['source_blockchain_id', - sa.text('nonce DESC'), 'status_id'], - unique=False) + sa.text('nonce DESC'), 'status_id'], unique=False) alembic.op.create_unique_constraint( - 'uq_transfers_source_blockchain_id_nonce_status_id', - 'transfers', ['source_blockchain_id', 'nonce', 'status_id'], - deferrable='True') + 'uq_transfers_source_blockchain_id_nonce_status_id', 'transfers', + ['source_blockchain_id', 'nonce', 'status_id'], deferrable='True') # ### end Alembic commands ### def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### alembic.op.drop_constraint( - 'uq_transfers_source_blockchain_id_nonce_status_id', - 'transfers', + 'uq_transfers_source_blockchain_id_nonce_status_id', 'transfers', type_='unique') alembic.op.drop_index('ix_transfers_source_blockchain_id_nonce_status_id', table_name='transfers') alembic.op.create_index( - 'ux_transfers_source_blockchain_id_nonce_status_id', - 'transfers', ['source_blockchain_id', 'nonce', 'status_id'], - unique=False) + 'ux_transfers_source_blockchain_id_nonce_status_id', 'transfers', + ['source_blockchain_id', 'nonce', 'status_id'], unique=False) # ### end Alembic commands ### diff --git a/pantos/servicenode/database/migrations/versions/bd913c5bfdfb_off_chain_bids.py b/pantos/servicenode/database/migrations/versions/bd913c5bfdfb_off_chain_bids.py index d9a7f60..ee9e52e 100644 --- a/pantos/servicenode/database/migrations/versions/bd913c5bfdfb_off_chain_bids.py +++ b/pantos/servicenode/database/migrations/versions/bd913c5bfdfb_off_chain_bids.py @@ -31,12 +31,10 @@ def upgrade() -> None: TransferTable.columns.fee == sqlalchemy.null()).values( fee=transfer_fee_subquery) connection.execute(transfer_fee_update_statement) - alembic.op.alter_column('transfers', - 'fee', - existing_type=sa.NUMERIC(precision=78, scale=0), - nullable=False) - alembic.op.drop_constraint('transfers_bid_id_fkey', - 'transfers', + alembic.op.alter_column('transfers', 'fee', + existing_type=sa.NUMERIC(precision=78, + scale=0), nullable=False) + alembic.op.drop_constraint('transfers_bid_id_fkey', 'transfers', type_='foreignkey') alembic.op.drop_column('transfers', 'bid_id') delete_bids_table_statement = sa.delete(BidTable) @@ -48,8 +46,7 @@ def upgrade() -> None: nullable=False)) alembic.op.drop_index('ux_bids_hub_contract_id_on_chain_bid_id', table_name='bids') - alembic.op.drop_constraint('bids_hub_contract_id_fkey', - 'bids', + alembic.op.drop_constraint('bids_hub_contract_id_fkey', 'bids', type_='foreignkey') alembic.op.create_foreign_key('bids_source_blockchain_id', 'bids', 'blockchains', ['source_blockchain_id'], @@ -65,9 +62,7 @@ def downgrade() -> None: # ### commands auto generated by Alembic - please adjust! ### alembic.op.add_column( 'bids', - sa.Column('hub_contract_id', - sa.INTEGER(), - autoincrement=False, + sa.Column('hub_contract_id', sa.INTEGER(), autoincrement=False, nullable=False)) alembic.op.add_column('transfers', sa.Column('bid_id', sa.Integer(), nullable=False)) @@ -77,27 +72,20 @@ def downgrade() -> None: ['bid_id'], ['id']) alembic.op.add_column( 'bids', - sa.Column('registered', - sqlalchemy.dialects.postgresql.TIMESTAMP(), - autoincrement=False, - nullable=True)) + sa.Column('registered', sqlalchemy.dialects.postgresql.TIMESTAMP(), + autoincrement=False, nullable=True)) alembic.op.add_column( 'bids', - sa.Column('on_chain_bid_id', - sa.BIGINT(), - autoincrement=False, + sa.Column('on_chain_bid_id', sa.BIGINT(), autoincrement=False, nullable=True)) alembic.op.add_column( 'bids', - sa.Column('unregistered', - sqlalchemy.dialects.postgresql.TIMESTAMP(), - autoincrement=False, - nullable=True)) - alembic.op.create_index('ux_bids_hub_contract_id_on_chain_bid_id', - 'bids', ['hub_contract_id', 'on_chain_bid_id'], + sa.Column('unregistered', sqlalchemy.dialects.postgresql.TIMESTAMP(), + autoincrement=False, nullable=True)) + alembic.op.create_index('ux_bids_hub_contract_id_on_chain_bid_id', 'bids', + ['hub_contract_id', 'on_chain_bid_id'], unique=False) - alembic.op.drop_constraint('bids_source_blockchain_id', - 'bids', + alembic.op.drop_constraint('bids_source_blockchain_id', 'bids', type_='foreignkey') alembic.op.drop_column('transfers', 'fee') alembic.op.drop_column('bids', 'valid_until') diff --git a/pantos/servicenode/database/migrations/versions/c4c46d14ca6a_initial_database_schema.py b/pantos/servicenode/database/migrations/versions/c4c46d14ca6a_initial_database_schema.py index 7ff8385..63e9154 100644 --- a/pantos/servicenode/database/migrations/versions/c4c46d14ca6a_initial_database_schema.py +++ b/pantos/servicenode/database/migrations/versions/c4c46d14ca6a_initial_database_schema.py @@ -70,8 +70,8 @@ def upgrade() -> None: ['hub_contract_id'], ['hub_contracts.id'], ), sa.PrimaryKeyConstraint('id')) - alembic.op.create_index('ux_bids_hub_contract_id_on_chain_bid_id', - 'bids', ['hub_contract_id', 'on_chain_bid_id'], + alembic.op.create_index('ux_bids_hub_contract_id_on_chain_bid_id', 'bids', + ['hub_contract_id', 'on_chain_bid_id'], unique=True) alembic.op.create_table( 'transfers', sa.Column('id', sa.Integer(), nullable=False), @@ -80,20 +80,17 @@ def upgrade() -> None: sa.Column('sender_address', sa.Text(), nullable=False), sa.Column('recipient_address', sa.Text(), nullable=False), sa.Column('source_token_contract_id', sa.Integer(), nullable=False), - sa.Column('destination_token_contract_id', - sa.Integer(), + sa.Column('destination_token_contract_id', sa.Integer(), nullable=False), sa.Column('amount', sa.Numeric(precision=78, scale=0), nullable=False), sa.Column('bid_id', sa.Integer(), nullable=False), - sa.Column('sender_nonce', - sa.Numeric(precision=78, scale=0), + sa.Column('sender_nonce', sa.Numeric(precision=78, scale=0), nullable=True), sa.Column('signature', sa.Text(), nullable=False), sa.Column('hub_contract_id', sa.Integer(), nullable=False), sa.Column('forwarder_contract_id', sa.Integer(), nullable=False), sa.Column('task_id', sa.Text(), nullable=True), - sa.Column('on_chain_transfer_id', - sa.Numeric(precision=78, scale=0), + sa.Column('on_chain_transfer_id', sa.Numeric(precision=78, scale=0), nullable=True), sa.Column('transaction_id', sa.Text(), nullable=True), sa.Column('nonce', sa.BigInteger(), nullable=True), @@ -130,19 +127,15 @@ def upgrade() -> None: ['status_id'], ['transfer_status.id'], ), sa.PrimaryKeyConstraint('id'), - sa.UniqueConstraint('forwarder_contract_id', - 'sender_address', - 'sender_nonce', - name='unique_sender_nonce'), + sa.UniqueConstraint('forwarder_contract_id', 'sender_address', + 'sender_nonce', name='unique_sender_nonce'), sa.UniqueConstraint('hub_contract_id', 'on_chain_transfer_id'), sa.UniqueConstraint('source_blockchain_id', 'transaction_id'), sa.UniqueConstraint('task_id')) alembic.op.create_index( - 'ux_transfers_source_blockchain_id_nonce_status_id', - 'transfers', + 'ux_transfers_source_blockchain_id_nonce_status_id', 'transfers', ['source_blockchain_id', - sa.text('nonce DESC'), 'status_id'], - unique=True) + sa.text('nonce DESC'), 'status_id'], unique=True) # ### end Alembic commands ### diff --git a/pantos/servicenode/database/models.py b/pantos/servicenode/database/models.py index d1d2ccc..e4033d9 100644 --- a/pantos/servicenode/database/models.py +++ b/pantos/servicenode/database/models.py @@ -116,9 +116,7 @@ class TokenContract(Base): blockchain = sqlalchemy.orm.relationship('Blockchain', back_populates='token_contracts') __table_args__ = (sqlalchemy.schema.Index( - 'ux_token_contracts_blockchain_id_address', - blockchain_id, - address, + 'ux_token_contracts_blockchain_id_address', blockchain_id, address, unique=True), ) @@ -147,17 +145,12 @@ class Bid(Base): """ __tablename__ = 'bids' source_blockchain_id = sqlalchemy.Column( - sqlalchemy.Integer, - sqlalchemy.ForeignKey('blockchains.id'), - nullable=False, - primary_key=True) + sqlalchemy.Integer, sqlalchemy.ForeignKey('blockchains.id'), + nullable=False, primary_key=True) destination_blockchain_id = sqlalchemy.Column( - sqlalchemy.Integer, - sqlalchemy.ForeignKey('blockchains.id'), - nullable=False, - primary_key=True) - execution_time = sqlalchemy.Column(sqlalchemy.Integer, - nullable=False, + sqlalchemy.Integer, sqlalchemy.ForeignKey('blockchains.id'), + nullable=False, primary_key=True) + execution_time = sqlalchemy.Column(sqlalchemy.Integer, nullable=False, primary_key=True) valid_until = sqlalchemy.Column(sqlalchemy.Integer, nullable=False) fee = sqlalchemy.Column( @@ -251,22 +244,18 @@ class Transfer(Base): __tablename__ = 'transfers' id = sqlalchemy.Column(sqlalchemy.Integer, primary_key=True) source_blockchain_id = sqlalchemy.Column( - sqlalchemy.Integer, - sqlalchemy.ForeignKey('blockchains.id'), + sqlalchemy.Integer, sqlalchemy.ForeignKey('blockchains.id'), nullable=False) destination_blockchain_id = sqlalchemy.Column( - sqlalchemy.Integer, - sqlalchemy.ForeignKey('blockchains.id'), + sqlalchemy.Integer, sqlalchemy.ForeignKey('blockchains.id'), nullable=False) sender_address = sqlalchemy.Column(sqlalchemy.Text, nullable=False) recipient_address = sqlalchemy.Column(sqlalchemy.Text, nullable=False) source_token_contract_id = sqlalchemy.Column( - sqlalchemy.Integer, - sqlalchemy.ForeignKey('token_contracts.id'), + sqlalchemy.Integer, sqlalchemy.ForeignKey('token_contracts.id'), nullable=False) destination_token_contract_id = sqlalchemy.Column( - sqlalchemy.Integer, - sqlalchemy.ForeignKey('token_contracts.id'), + sqlalchemy.Integer, sqlalchemy.ForeignKey('token_contracts.id'), nullable=False) amount = sqlalchemy.Column( # Large enough for a 256-bit unsigned integer @@ -281,12 +270,10 @@ class Transfer(Base): sqlalchemy.Numeric(precision=78, scale=0)) signature = sqlalchemy.Column(sqlalchemy.Text, nullable=False) hub_contract_id = sqlalchemy.Column( - sqlalchemy.Integer, - sqlalchemy.ForeignKey('hub_contracts.id'), + sqlalchemy.Integer, sqlalchemy.ForeignKey('hub_contracts.id'), nullable=False) forwarder_contract_id = sqlalchemy.Column( - sqlalchemy.Integer, - sqlalchemy.ForeignKey('forwarder_contracts.id'), + sqlalchemy.Integer, sqlalchemy.ForeignKey('forwarder_contracts.id'), nullable=False) task_id = sqlalchemy.Column(sqlalchemy.Text, unique=True) on_chain_transfer_id = sqlalchemy.Column( @@ -297,8 +284,7 @@ class Transfer(Base): status_id = sqlalchemy.Column(sqlalchemy.Integer, sqlalchemy.ForeignKey('transfer_status.id'), nullable=False) - created = sqlalchemy.Column(sqlalchemy.DateTime, - nullable=False, + created = sqlalchemy.Column(sqlalchemy.DateTime, nullable=False, default=datetime.datetime.utcnow) updated = sqlalchemy.Column(sqlalchemy.DateTime) source_blockchain = sqlalchemy.orm.relationship( @@ -319,17 +305,13 @@ class Transfer(Base): forwarder_contract = sqlalchemy.orm.relationship('ForwarderContract') status = sqlalchemy.orm.relationship('TransferStatus') __table_args__ = ( - sqlalchemy.UniqueConstraint(forwarder_contract_id, - sender_address, + sqlalchemy.UniqueConstraint(forwarder_contract_id, sender_address, sender_nonce, name=UNIQUE_SENDER_NONCE_CONSTRAINT), sqlalchemy.UniqueConstraint(hub_contract_id, on_chain_transfer_id), sqlalchemy.UniqueConstraint(source_blockchain_id, transaction_id), sqlalchemy.UniqueConstraint( - source_blockchain_id, - nonce, - status_id, - deferrable=True, + source_blockchain_id, nonce, status_id, deferrable=True, name='uq_transfers_source_blockchain_id_nonce_status_id'), sqlalchemy.schema.Index( 'ix_transfers_source_blockchain_id_nonce_status_id', diff --git a/pantos/servicenode/plugins/base.py b/pantos/servicenode/plugins/base.py index c46fec0..6aba847 100644 --- a/pantos/servicenode/plugins/base.py +++ b/pantos/servicenode/plugins/base.py @@ -38,7 +38,6 @@ class Bid: class BidPlugin(abc.ABC): - @abc.abstractmethod def get_bids( self, source_blockchain_id: int, destination_blockchain_id: int, diff --git a/pantos/servicenode/plugins/bids.py b/pantos/servicenode/plugins/bids.py index a5005ff..d8d48d4 100644 --- a/pantos/servicenode/plugins/bids.py +++ b/pantos/servicenode/plugins/bids.py @@ -61,7 +61,6 @@ class ConfigFileBidPlugin(BidPlugin): delay : int The delay in seconds until the next bid calculation. """ - def __init__(self): """Initializes the plugin. """ diff --git a/pantos/servicenode/restapi.py b/pantos/servicenode/restapi.py index 81301ba..4a5930f 100644 --- a/pantos/servicenode/restapi.py +++ b/pantos/servicenode/restapi.py @@ -58,8 +58,7 @@ class _TransferSchema(marshmallow.Schema): """ source_blockchain_id = marshmallow.fields.Integer(required=True) destination_blockchain_id = marshmallow.fields.Integer( - required=True, - validate=marshmallow.validate.OneOf( + required=True, validate=marshmallow.validate.OneOf( [blockchain.value for blockchain in Blockchain])) sender_address = marshmallow.fields.String(required=True) recipient_address = marshmallow.fields.String(required=True) @@ -126,13 +125,11 @@ def __check_valid_recipient_address(self, if not get_blockchain_client( destination_blockchain).is_valid_recipient_address( recipient_address): - _logger.warning('new transfer request: invalid recipient address', - extra={ - 'recipient_address': - recipient_address, - 'destination_blockchain': - destination_blockchain.name - }) + _logger.warning( + 'new transfer request: invalid recipient address', extra={ + 'recipient_address': recipient_address, + 'destination_blockchain': destination_blockchain.name + }) raise marshmallow.ValidationError( 'recipient address must be a valid blockchain ' 'address, different from the 0 address on ' @@ -205,12 +202,10 @@ class _BidsSchema(marshmallow.Schema): """ source_blockchain = marshmallow.fields.Integer( - required=True, - validate=marshmallow.validate.OneOf( + required=True, validate=marshmallow.validate.OneOf( [blockchain.value for blockchain in Blockchain])) destination_blockchain = marshmallow.fields.Integer( - required=True, - validate=marshmallow.validate.OneOf( + required=True, validate=marshmallow.validate.OneOf( [blockchain.value for blockchain in Blockchain])) @@ -218,7 +213,6 @@ class _Transfer(flask_restful.Resource): """RESTful resource for token transfer requests. """ - def post(self) -> flask.Response: try: time_received = time.time() @@ -248,7 +242,6 @@ class _TransferStatus(flask_restful.Resource): """RESTful resource for token transfer status requests. """ - def get(self, task_id: str) -> flask.Response: try: task_id_uuid = _TransferStatusSchema().load({'task_id': task_id}) @@ -268,32 +261,25 @@ def get(self, task_id: str) -> flask.Response: exc_info=True) internal_server_error() return ok_response({ - 'task_id': - str(task_id_uuid), - 'source_blockchain_id': - find_transfer_response.source_blockchain.value, - 'destination_blockchain_id': - find_transfer_response.destination_blockchain.value, - 'sender_address': - find_transfer_response.sender_address, - 'recipient_address': - find_transfer_response.recipient_address, - 'source_token_address': - find_transfer_response.source_token_address, - 'destination_token_address': - find_transfer_response.destination_token_address, - 'amount': - find_transfer_response.amount, - 'fee': - find_transfer_response.fee, - 'status': - find_transfer_response.status.to_public_status().name.lower(), - 'transfer_id': - '' if find_transfer_response.transfer_id is None else - find_transfer_response.transfer_id, - 'transaction_id': - '' if find_transfer_response.transaction_id is None else - find_transfer_response.transaction_id + 'task_id': str(task_id_uuid), + 'source_blockchain_id': find_transfer_response.source_blockchain. + value, + 'destination_blockchain_id': find_transfer_response. + destination_blockchain.value, + 'sender_address': find_transfer_response.sender_address, + 'recipient_address': find_transfer_response.recipient_address, + 'source_token_address': find_transfer_response. + source_token_address, + 'destination_token_address': find_transfer_response. + destination_token_address, + 'amount': find_transfer_response.amount, + 'fee': find_transfer_response.fee, + 'status': find_transfer_response.status.to_public_status().name. + lower(), + 'transfer_id': '' if find_transfer_response.transfer_id is None + else find_transfer_response.transfer_id, + 'transaction_id': '' if find_transfer_response.transaction_id + is None else find_transfer_response.transaction_id }) @@ -301,7 +287,6 @@ class _Bids(flask_restful.Resource): """RESTful resource for token transfer bids. """ - def get(self) -> flask.Response: try: query_arguments = flask_restful.request.args diff --git a/requirements.txt b/requirements.txt deleted file mode 100644 index 033f9c7..0000000 --- a/requirements.txt +++ /dev/null @@ -1,14 +0,0 @@ -. -bandit==1.7.5 -flake8==6.0.0 -isort==5.12.0 -mypy==1.0.1 -pre-commit==3.3.3 -pytest==7.4.0 -pytest-cov==4.1.0 -pytest-mock==3.11.1 -types-PyYAML==6.0.12.10 -web3[tester]==6.5.0 -wheel==0.40.0 -yapf==0.40.1 -eth-tester==0.9.0b1 diff --git a/service-node-config.yml b/service-node-config.yml new file mode 100644 index 0000000..888c7a9 --- /dev/null +++ b/service-node-config.yml @@ -0,0 +1,222 @@ +application: + debug: !ENV tag:yaml.org,2002:bool ${APP_DEBUG:false} + host: !ENV ${APP_HOST:127.0.0.1} + port: !ENV tag:yaml.org,2002:int ${APP_PORT:443} + url: !ENV ${APP_URL} + log: + format: !ENV ${APP_LOG_FORMAT:human_readable} + console: + enabled: !ENV tag:yaml.org,2002:bool ${APP_LOG_CONSOLE_ENABLED:true} + file: + enabled: !ENV tag:yaml.org,2002:bool ${APP_LOG_FILE_ENABLED:true} + name: !ENV ${APP_LOG_FILE_NAME:/var/log/pantos/service-node.log} + max_bytes: !ENV tag:yaml.org,2002:int ${APP_LOG_FILE_MAX_BYTES:104857600} + backup_count: !ENV tag:yaml.org,2002:int ${APP_LOG_FILE_BACKUP_COUNT:10} + +database: + url: !ENV ${DB_URL} + pool_size: !ENV tag:yaml.org,2002:int ${DB_POOL_SIZE:20} + max_overflow: !ENV tag:yaml.org,2002:int ${DB_MAX_OVERFLOW:50} + echo: !ENV tag:yaml.org,2002:bool ${DB_ECHO:false} + alembic_config: !ENV ${DB_ALEMBIC_CONFIG:/etc/pantos/service-node-alembic.ini} + apply_migrations: !ENV tag:yaml.org,2002:bool ${DB_APPLY_MIGRATIONS:true} + +celery: + broker: !ENV ${CELERY_BROKER} + backend: !ENV ${CELERY_BACKEND} + log: + format: !ENV ${CELERY_LOG_FORMAT:human_readable} + console: + enabled: !ENV tag:yaml.org,2002:bool ${CELERY_LOG_CONSOLE_ENABLED:true} + file: + enabled: !ENV tag:yaml.org,2002:bool ${CELERY_LOG_FILE_ENABLED:true} + name: !ENV ${CELERY_LOG_FILE_NAME:/var/log/pantos/service-node-worker.log} + max_bytes: !ENV tag:yaml.org,2002:int ${CELERY_LOG_FILE_MAX_BYTES:104857600} + backup_count: !ENV tag:yaml.org,2002:int ${CELERY_LOG_FILE_BACKUP_COUNT:10} + +tasks: + confirm_transfer: + interval: !ENV tag:yaml.org,2002:int ${TASKS_CONFIRM_TRANSFER_INTERVAL:30} + retry_interval_after_error: !ENV tag:yaml.org,2002:int ${TASKS_CONFIRM_TRANSFER_RETRY_INTERVAL_AFTER_ERROR:60} + execute_transfer: + retry_interval_after_error: !ENV tag:yaml.org,2002:int ${TASKS_EXECUTE_TRANSFER_RETRY_INTERVAL_AFTER_ERROR:30} + +plugins: + bids: + class: pantos.servicenode.plugins.bids.ConfigFileBidPlugin + arguments: + file_path: !ENV ${PLUGINS_BIDS_ARGUMENTS_FILE_PATH:/etc/pantos/service-node-bids.yml} + +signer: + pem: !ENV ${SIGNER_PEM:/etc/pantos/service-node-signer.pem} + pem_password: !ENV ${SIGNER_PEM_PASSWORD} + +blockchains: + avalanche: + active: !ENV tag:yaml.org,2002:bool ${AVALANCHE_ACTIVE:true} + registered: !ENV tag:yaml.org,2002:bool ${AVALANCHE_REGISTERED:true} + unstaking_address: !ENV ${AVALANCHE_UNSTAKING_ADDRESS:0x726265A9e352F2e9f15F255957840992803cED7d} + private_key: !ENV ${AVALANCHE_PRIVATE_KEY:/etc/pantos/service-node.keystore} + private_key_password: !ENV ${AVALANCHE_PRIVATE_KEY_PASSWORD:} + provider: !ENV ${AVALANCHE_PROVIDER:https://api.avax-test.network/ext/bc/C/rpc} + fallback_providers: + - !ENV ${AVALANCHE_FALLBACK_PROVIDER:https://api.avax-test.network/ext/bc/C/rpc} + average_block_time: !ENV tag:yaml.org,2002:int ${AVALANCHE_AVERAGE_BLOCK_TIME:3} + provider_timeout: !ENV tag:yaml.org,2002:int ${AVALANCHE_PROVIDER_TIMEOUT:100} + chain_id: !ENV tag:yaml.org,2002:int ${AVALANCHE_CHAIN_ID:43113} + hub: !ENV ${AVALANCHE_HUB:0xbafFb84601BeC1FCb4B842f8917E3eA850781BE7} + forwarder: !ENV ${AVALANCHE_FORWARDER:0xfd7D081b7426aAb19CDc63E245313Ce9fF559cDC} + pan_token: !ENV ${AVALANCHE_PAN_TOKEN:0xC892F1D09a7BEF98d65e7f9bD4642d36BC506441} + confirmations: !ENV tag:yaml.org,2002:int ${AVALANCHE_CONFIRMATIONS:20} + min_adaptable_fee_per_gas: !ENV tag:yaml.org,2002:int ${AVALANCHE_MIN_ADAPTABLE_FEE_PER_GAS:1000000000} + #max_total_fee_per_gas: !ENV tag:yaml.org,2002:int ${AVALANCHE_MAX_TOTAL_FEE_PER_GAS: } + adaptable_fee_increase_factor: !ENV tag:yaml.org,2002:float ${AVALANCHE_ADAPTABLE_FEE_INCREASE_FACTOR:1.101} + blocks_until_resubmission: !ENV tag:yaml.org,2002:int ${AVALANCHE_BLOCKS_UNTIL_RESUBMISSION:20} + stake: !ENV tag:yaml.org,2002:int ${AVALANCHE_STAKE:10000000000000} + bnb_chain: + active: !ENV tag:yaml.org,2002:bool ${BNB_ACTIVE:true} + registered: !ENV tag:yaml.org,2002:bool ${BNB_REGISTERED:true} + unstaking_address: !ENV ${BNB_UNSTAKING_ADDRESS:0x726265A9e352F2e9f15F255957840992803cED7d} + private_key: !ENV ${BNB_PRIVATE_KEY:/etc/pantos/service-node.keystore} + private_key_password: !ENV ${BNB_PRIVATE_KEY_PASSWORD:} + provider: !ENV ${BNB_PROVIDER:https://data-seed-prebsc-1-s1.binance.org:8545/} + fallback_providers: + - !ENV ${BNB_FALLBACK_PROVIDER:https://data-seed-prebsc-1-s1.binance.org:8545/} + average_block_time: !ENV tag:yaml.org,2002:int ${BNB_AVERAGE_BLOCK_TIME:3} + provider_timeout: !ENV tag:yaml.org,2002:int ${BNB_PROVIDER_TIMEOUT:100} + chain_id: !ENV tag:yaml.org,2002:int ${BNB_CHAIN_ID:97} + hub: !ENV ${BNB_HUB:0xFB37499DC5401Dc39a0734df1fC7924d769721d5} + forwarder: !ENV ${BNB_FORWARDER:0x8d1A4C7bc5f327f30895150c4596E3db6Eb48562} + pan_token: !ENV ${BNB_PAN_TOKEN:0xC892F1D09a7BEF98d65e7f9bD4642d36BC506441} + confirmations: !ENV tag:yaml.org,2002:int ${BNB_CONFIRMATIONS:20} + min_adaptable_fee_per_gas: !ENV tag:yaml.org,2002:int ${BNB_MIN_ADAPTABLE_FEE_PER_GAS:5000000000} + #max_total_fee_per_gas: !ENV tag:yaml.org,2002:int ${BNB_MAX_TOTAL_FEE_PER_GAS: } + adaptable_fee_increase_factor: !ENV tag:yaml.org,2002:float ${BNB_ADAPTABLE_FEE_INCREASE_FACTOR:1.101} + blocks_until_resubmission: !ENV tag:yaml.org,2002:int ${BNB_BLOCKS_UNTIL_RESUBMISSION:20} + stake: !ENV tag:yaml.org,2002:int ${BNB_STAKE:10000000000000} + celo: + active: !ENV tag:yaml.org,2002:bool ${CELO_ACTIVE:true} + registered: !ENV tag:yaml.org,2002:bool ${CELO_REGISTERED:true} + unstaking_address: !ENV ${CELO_UNSTAKING_ADDRESS:0x726265A9e352F2e9f15F255957840992803cED7d} + private_key: !ENV ${CELO_PRIVATE_KEY:/etc/pantos/service-node.keystore} + private_key_password: !ENV ${CELO_PRIVATE_KEY_PASSWORD:} + provider: !ENV ${CELO_PROVIDER:https://alfajores-forno.celo-testnet.org} + fallback_providers: + - !ENV ${CELO_FALLBACK_PROVIDER:https://alfajores-forno.celo-testnet.org} + average_block_time: !ENV tag:yaml.org,2002:int ${CELO_AVERAGE_BLOCK_TIME:5} + provider_timeout: !ENV tag:yaml.org,2002:int ${CELO_PROVIDER_TIMEOUT:100} + chain_id: !ENV tag:yaml.org,2002:int ${CELO_CHAIN_ID:44787} + hub: !ENV ${CELO_HUB:0x8389B9A7608dbf52a699b998f309883257923C0E} + forwarder: !ENV ${CELO_FORWARDER:0x38dd7589fF20370b3BA5d9C09ac1d16Ed3496435} + pan_token: !ENV ${CELO_PAN_TOKEN:0x5538e600dc919f72858dd4D4F5E4327ec6f2af60} + confirmations: !ENV tag:yaml.org,2002:int ${CELO_CONFIRMATIONS:3} + min_adaptable_fee_per_gas: !ENV tag:yaml.org,2002:int ${CELO_MIN_ADAPTABLE_FEE_PER_GAS:1000000000} + #max_total_fee_per_gas: !ENV tag:yaml.org,2002:int ${CELO_MAX_TOTAL_FEE_PER_GAS: } + adaptable_fee_increase_factor: !ENV tag:yaml.org,2002:float ${CELO_ADAPTABLE_FEE_INCREASE_FACTOR:1.101} + blocks_until_resubmission: !ENV tag:yaml.org,2002:int ${CELO_BLOCKS_UNTIL_RESUBMISSION:20} + stake: !ENV tag:yaml.org,2002:int ${CELO_STAKE:10000000000000} + cronos: + active: !ENV tag:yaml.org,2002:bool ${CRONOS_ACTIVE:true} + registered: !ENV tag:yaml.org,2002:bool ${CRONOS_REGISTERED:true} + unstaking_address: !ENV ${CRONOS_UNSTAKING_ADDRESS:0x726265A9e352F2e9f15F255957840992803cED7d} + private_key: !ENV ${CRONOS_PRIVATE_KEY:/etc/pantos/service-node.keystore} + private_key_password: !ENV ${CRONOS_PRIVATE_KEY_PASSWORD:} + provider: !ENV ${CRONOS_PROVIDER:https://evm-t3.cronos.org} + fallback_providers: + - !ENV ${CRONOS_FALLBACK_PROVIDER:https://cronos-testnet.crypto.org:8545/} + average_block_time: !ENV tag:yaml.org,2002:int ${CRONOS_AVERAGE_BLOCK_TIME:5} + provider_timeout: !ENV tag:yaml.org,2002:int ${CRONOS_PROVIDER_TIMEOUT:100} + chain_id: !ENV tag:yaml.org,2002:int ${CRONOS_CHAIN_ID:338} + hub: !ENV ${CRONOS_HUB:0x0Cfb3c7C11A33BEf124A9D86073e73932b9AbF90} + forwarder: !ENV ${CRONOS_FORWARDER:0x38dd7589fF20370b3BA5d9C09ac1d16Ed3496435} + pan_token: !ENV ${CRONOS_PAN_TOKEN:0x5538e600dc919f72858dd4D4F5E4327ec6f2af60} + confirmations: !ENV tag:yaml.org,2002:int ${CRONOS_CONFIRMATIONS:3} + min_adaptable_fee_per_gas: !ENV tag:yaml.org,2002:int ${CRONOS_MIN_ADAPTABLE_FEE_PER_GAS:1000000000} + #max_total_fee_per_gas: !ENV tag:yaml.org,2002:int ${CRONOS_MAX_TOTAL_FEE_PER_GAS: } + adaptable_fee_increase_factor: !ENV tag:yaml.org,2002:float ${CRONOS_ADAPTABLE_FEE_INCREASE_FACTOR:1.101} + blocks_until_resubmission: !ENV tag:yaml.org,2002:int ${CRONOS_BLOCKS_UNTIL_RESUBMISSION:20} + stake: !ENV tag:yaml.org,2002:int ${CRONOS_STAKE:10000000000000} + ethereum: + active: !ENV tag:yaml.org,2002:bool ${ETHEREUM_ACTIVE:true} + registered: !ENV tag:yaml.org,2002:bool ${ETHEREUM_REGISTERED:true} + unstaking_address: !ENV ${ETHEREUM_UNSTAKING_ADDRESS:0x726265A9e352F2e9f15F255957840992803cED7d} + private_key: !ENV ${ETHEREUM_PRIVATE_KEY:/etc/pantos/service-node.keystore} + private_key_password: !ENV ${ETHEREUM_PRIVATE_KEY_PASSWORD:} + provider: !ENV ${ETHEREUM_PROVIDER:https://ethereum-holesky.publicnode.com} + fallback_providers: + - !ENV ${ETHEREUM_FALLBACK_PROVIDER:https://ethereum-holesky.publicnode.com} + average_block_time: !ENV tag:yaml.org,2002:int ${ETHEREUM_AVERAGE_BLOCK_TIME:14} + provider_timeout: !ENV tag:yaml.org,2002:int ${ETHEREUM_PROVIDER_TIMEOUT:100} + chain_id: !ENV tag:yaml.org,2002:int ${ETHEREUM_CHAIN_ID:17000} + hub: !ENV ${ETHEREUM_HUB:0x5e447968d4a177fE7bFB8877cA12aE20Bd60dD85} + forwarder: !ENV ${ETHEREUM_FORWARDER:0xce5FE7168424ED2246a3dd79214f2D69a7Edc0BB} + pan_token: !ENV ${ETHEREUM_PAN_TOKEN:0x7EFfCc0a130E452c2FB78bFEDBd02a33E03FD50d} + confirmations: !ENV tag:yaml.org,2002:int ${ETHEREUM_CONFIRMATIONS:20} + min_adaptable_fee_per_gas: !ENV tag:yaml.org,2002:int ${ETHEREUM_MIN_ADAPTABLE_FEE_PER_GAS:1000000000} + #max_total_fee_per_gas: !ENV tag:yaml.org,2002:int ${ETHEREUM_MAX_TOTAL_FEE_PER_GAS: } + adaptable_fee_increase_factor: !ENV tag:yaml.org,2002:float ${ETHEREUM_ADAPTABLE_FEE_INCREASE_FACTOR:1.101} + blocks_until_resubmission: !ENV tag:yaml.org,2002:int ${ETHEREUM_BLOCKS_UNTIL_RESUBMISSION:20} + stake: !ENV tag:yaml.org,2002:int ${ETHEREUM_STAKE:10000000000000} + fantom: + active: !ENV tag:yaml.org,2002:bool ${FANTOM_ACTIVE:true} + registered: !ENV tag:yaml.org,2002:bool ${FANTOM_REGISTERED:true} + unstaking_address: !ENV ${FANTOM_UNSTAKING_ADDRESS:0x726265A9e352F2e9f15F255957840992803cED7d} + private_key: !ENV ${FANTOM_PRIVATE_KEY:/etc/pantos/service-node.keystore} + private_key_password: !ENV ${FANTOM_PRIVATE_KEY_PASSWORD:} + provider: !ENV ${FANTOM_PROVIDER:https://rpc.ankr.com/fantom_testnet} + fallback_providers: + - !ENV ${FANTOM_FALLBACK_PROVIDER:https://rpc.ankr.com/fantom_testnet} + average_block_time: !ENV tag:yaml.org,2002:int ${FANTOM_AVERAGE_BLOCK_TIME:1} + provider_timeout: !ENV tag:yaml.org,2002:int ${FANTOM_PROVIDER_TIMEOUT:100} + chain_id: !ENV tag:yaml.org,2002:int ${FANTOM_CHAIN_ID:4002} + hub: !ENV ${FANTOM_HUB:0x4BC6A71D4C3D6170d0Db849fE19b8DbA18f1a7F5} + forwarder: !ENV ${FANTOM_FORWARDER:0xbBbebAB1c109De08599ae17e2977cD7D91eA2D3b} + pan_token: !ENV ${FANTOM_PAN_TOKEN:0x5538e600dc919f72858dd4D4F5E4327ec6f2af60} + confirmations: !ENV tag:yaml.org,2002:int ${FANTOM_CONFIRMATIONS:6} + min_adaptable_fee_per_gas: !ENV tag:yaml.org,2002:int ${FANTOM_MIN_ADAPTABLE_FEE_PER_GAS:1000000000} + #max_total_fee_per_gas: !ENV tag:yaml.org,2002:int ${FANTOM_MAX_TOTAL_FEE_PER_GAS: } + adaptable_fee_increase_factor: !ENV tag:yaml.org,2002:float ${FANTOM_ADAPTABLE_FEE_INCREASE_FACTOR:1.101} + blocks_until_resubmission: !ENV tag:yaml.org,2002:int ${FANTOM_BLOCKS_UNTIL_RESUBMISSION:20} + stake: !ENV tag:yaml.org,2002:int ${FANTOM_STAKE:10000000000000} + polygon: + active: !ENV tag:yaml.org,2002:bool ${POLYGON_ACTIVE:true} + registered: !ENV tag:yaml.org,2002:bool ${POLYGON_REGISTERED:true} + unstaking_address: !ENV ${POLYGON_UNSTAKING_ADDRESS:0x726265A9e352F2e9f15F255957840992803cED7d} + private_key: !ENV ${POLYGON_PRIVATE_KEY:/etc/pantos/service-node.keystore} + private_key_password: !ENV ${POLYGON_PRIVATE_KEY_PASSWORD:} + provider: !ENV ${POLYGON_PROVIDER:https://rpc.ankr.com/polygon_mumbai} + fallback_providers: + - !ENV ${POLYGON_FALLBACK_PROVIDER:https://rpc.ankr.com/polygon_mumbai} + average_block_time: !ENV tag:yaml.org,2002:int ${POLYGON_AVERAGE_BLOCK_TIME:3} + provider_timeout: !ENV tag:yaml.org,2002:int ${POLYGON_PROVIDER_TIMEOUT:100} + chain_id: !ENV tag:yaml.org,2002:int ${POLYGON_CHAIN_ID:80001} + hub: !ENV ${POLYGON_HUB:0x5C4B92cd0A956dedc14AF31fD474931540D8277B} + forwarder: !ENV ${POLYGON_FORWARDER:0xC458D148d1Cac769239629e744be37eDEf4F06A6} + pan_token: !ENV ${POLYGON_PAN_TOKEN:0xC892F1D09a7BEF98d65e7f9bD4642d36BC506441} + confirmations: !ENV tag:yaml.org,2002:int ${POLYGON_CONFIRMATIONS:200} + min_adaptable_fee_per_gas: !ENV tag:yaml.org,2002:int ${POLYGON_MIN_ADAPTABLE_FEE_PER_GAS:1000000000} + #max_total_fee_per_gas: !ENV tag:yaml.org,2002:int ${POLYGON_MAX_TOTAL_FEE_PER_GAS: } + adaptable_fee_increase_factor: !ENV tag:yaml.org,2002:float ${POLYGON_ADAPTABLE_FEE_INCREASE_FACTOR:1.101} + blocks_until_resubmission: !ENV tag:yaml.org,2002:int ${POLYGON_BLOCKS_UNTIL_RESUBMISSION:20} + stake: !ENV tag:yaml.org,2002:int ${POLYGON_STAKE:10000000000000} + solana: + active: !ENV tag:yaml.org,2002:bool ${SOLANA_ACTIVE:false} + registered: !ENV tag:yaml.org,2002:bool ${SOLANA_REGISTERED:true} + unstaking_address: !ENV ${SOLANA_UNSTAKING_ADDRESS:0x726265A9e352F2e9f15F255957840992803cED7d:' '} + private_key: !ENV ${SOLANA_PRIVATE_KEY:' '} + private_key_password: !ENV ${SOLANA_PRIVATE_KEY_PASSWORD:} + provider: !ENV ${SOLANA_PROVIDER:} + fallback_providers: + - !ENV ${SOLANA_FALLBACK_PROVIDER:} + average_block_time: !ENV tag:yaml.org,2002:int ${SOLANA_AVERAGE_BLOCK_TIME:1} + chain_id: !ENV tag:yaml.org,2002:int ${SOLANA_CHAIN_ID:-1} + hub: !ENV ${SOLANA_HUB:' '} + forwarder: !ENV ${SOLANA_FORWARDER:' '} + pan_token: !ENV ${SOLANA_PAN_TOKEN:' '} + confirmations: !ENV tag:yaml.org,2002:int ${SOLANA_CONFIRMATIONS:1} + min_adaptable_fee_per_gas: !ENV tag:yaml.org,2002:int ${SOLANA_MIN_ADAPTABLE_FEE_PER_GAS:1000000000} + #max_total_fee_per_gas: !ENV tag:yaml.org,2002:int ${SOLANA_MAX_TOTAL_FEE_PER_GAS:' '} + adaptable_fee_increase_factor: !ENV tag:yaml.org,2002:float ${SOLANA_ADAPTABLE_FEE_INCREASE_FACTOR:1.101} + blocks_until_resubmission: !ENV tag:yaml.org,2002:int ${SOLANA_BLOCKS_UNTIL_RESUBMISSION:20} + stake: !ENV tag:yaml.org,2002:int ${SOLANA_STAKE:10000000000000} + \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100644 index b4aa7ad..0000000 --- a/setup.py +++ /dev/null @@ -1,30 +0,0 @@ -import os - -import setuptools # type: ignore - -setuptools.setup( - name='pantos-service-node', - version=os.getenv('PANTOS_SERVICE_NODE_VERSION', '0.0.0'), - description='Service node reference implementation for the ' - 'Pantos multi-blockchain system', - packages=setuptools.find_packages(), - package_data={ - 'pantos': [ - 'service-node-config.yml', 'service-node-config.env', - 'alembic.ini', 'bids.yml' - ], - 'pantos.common.blockchains.contracts': ['*.abi'], - 'pantos.servicenode.blockchains.contracts': ['*.abi'] - }, - install_requires=[ - 'alembic==1.11.1', 'celery==5.3.1', 'Cerberus==1.3.4', 'Flask==2.3.2', - 'Flask-Cors==4.0.0', 'Flask-RESTful==0.3.10', 'marshmallow==3.19.0', - 'psycopg2-binary==2.9.6', 'PyYAML==6.0.1', 'SQLAlchemy==2.0.18', - 'web3==6.5.0', 'JSON-log-formatter==0.5.2', 'pyaml-env==1.2.1', - 'python-dotenv==1.0.1', 'hexbytes==0.3.1' - ], - url='https://github.com/pantos-io/servicenode', - author='Pantos', - long_description=('Service node reference implementation for' - ' the Pantos multi-blockchain system'), -) diff --git a/sonar-project.properties b/sonar-project.properties new file mode 100644 index 0000000..2b4017b --- /dev/null +++ b/sonar-project.properties @@ -0,0 +1,5 @@ +sonar.projectKey=pantos-io_servicenode +sonar.organization=pantos-io +sonar.python.coverage.reportPaths=coverage-3.12.xml +sonar.python.version=3.12 +sonar.coverage.exclusions=**/tests/**,**/migrations/** diff --git a/submodules/common b/submodules/common deleted file mode 160000 index 8825915..0000000 --- a/submodules/common +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 882591580986ac1dbc967d8668eed69a48ab2e82 diff --git a/tests/blockchains/test_base.py b/tests/blockchains/test_base.py index 83fbd6f..abe15b1 100644 --- a/tests/blockchains/test_base.py +++ b/tests/blockchains/test_base.py @@ -36,11 +36,9 @@ @pytest.fixture(scope='module') @unittest.mock.patch( 'pantos.servicenode.blockchains.base.initialize_blockchain_utilities') -@unittest.mock.patch.object(BlockchainClient, - '_get_config', +@unittest.mock.patch.object(BlockchainClient, '_get_config', return_value=_MOCK_CONFIG) -@unittest.mock.patch.object(BlockchainClient, - 'get_blockchain', +@unittest.mock.patch.object(BlockchainClient, 'get_blockchain', return_value=Blockchain(0)) @unittest.mock.patch.object(BlockchainClient, '__abstractmethods__', set()) def blockchain_client(mock_get_blockchain, mock_get_config, @@ -50,11 +48,9 @@ def blockchain_client(mock_get_blockchain, mock_get_config, @unittest.mock.patch( 'pantos.servicenode.blockchains.base.initialize_blockchain_utilities') -@unittest.mock.patch.object(BlockchainClient, - '_get_config', +@unittest.mock.patch.object(BlockchainClient, '_get_config', return_value=_MOCK_CONFIG) -@unittest.mock.patch.object(BlockchainClient, - 'get_blockchain', +@unittest.mock.patch.object(BlockchainClient, 'get_blockchain', return_value=Blockchain(0)) @unittest.mock.patch.object(BlockchainClient, '__abstractmethods__', set()) def test_init_correct(mock_get_blockchain, mock_get_config, @@ -66,14 +62,11 @@ def test_init_correct(mock_get_blockchain, mock_get_config, @unittest.mock.patch( 'pantos.servicenode.blockchains.base.initialize_blockchain_utilities', side_effect=BlockchainUtilitiesError('')) -@unittest.mock.patch.object(BlockchainClient, - '_create_error', +@unittest.mock.patch.object(BlockchainClient, '_create_error', return_value=BlockchainClientError('')) -@unittest.mock.patch.object(BlockchainClient, - '_get_config', +@unittest.mock.patch.object(BlockchainClient, '_get_config', return_value=_MOCK_CONFIG) -@unittest.mock.patch.object(BlockchainClient, - 'get_blockchain', +@unittest.mock.patch.object(BlockchainClient, 'get_blockchain', return_value=Blockchain(0)) @unittest.mock.patch.object(BlockchainClient, '__abstractmethods__', set()) def test_init_error(mock_get_blockchain, mock_get_config, mock_create_error, @@ -97,8 +90,7 @@ def test_get_transfer_submission_status_not_completed(mock_get_utilities, @pytest.mark.parametrize( 'transaction_status', [TransactionStatus.CONFIRMED, TransactionStatus.REVERTED]) -@unittest.mock.patch.object(BlockchainClient, - '_read_on_chain_transfer_id', +@unittest.mock.patch.object(BlockchainClient, '_read_on_chain_transfer_id', return_value=_ON_CHAIN_TRANSFER_ID) @unittest.mock.patch.object(BlockchainClient, '_get_utilities') def test_get_transfer_submission_status_completed( @@ -117,8 +109,7 @@ def test_get_transfer_submission_status_completed( @unittest.mock.patch.object(BlockchainClient, '_get_utilities') -@unittest.mock.patch.object(BlockchainClient, - 'get_error_class', +@unittest.mock.patch.object(BlockchainClient, 'get_error_class', return_value=BlockchainClientError) def test_get_transfer_submission_status_error(mock_get_error_class, mock_get_utilities, diff --git a/tests/blockchains/test_ethereum.py b/tests/blockchains/test_ethereum.py index d30d268..a671c79 100644 --- a/tests/blockchains/test_ethereum.py +++ b/tests/blockchains/test_ethereum.py @@ -20,25 +20,17 @@ from pantos.servicenode.blockchains.ethereum import EthereumClientError _TRANSFER_FROM_TRANSACTION_RECEIPT = web3.datastructures.AttributeDict({ - 'blockHash': - hexbytes.HexBytes( + 'blockHash': hexbytes.HexBytes( '0x24aa438ba5aa72634a09f77acefb5c8cce1261b44681e72488d4405e311fa9a2'), - 'blockNumber': - 18862558, - 'contractAddress': - None, - 'cumulativeGasUsed': - 697584, - 'effectiveGasPrice': - 8000000000, - 'from': - '0xaAE34Ec313A97265635B8496468928549cdd4AB7', - 'gasUsed': - 129822, + 'blockNumber': 18862558, + 'contractAddress': None, + 'cumulativeGasUsed': 697584, + 'effectiveGasPrice': 8000000000, + 'from': '0xaAE34Ec313A97265635B8496468928549cdd4AB7', + 'gasUsed': 129822, 'logs': [ web3.datastructures.AttributeDict({ - 'address': - '0xE1b042d1e27BF7B2bee000a23C59f9eB0aC6Fdce', + 'address': '0xE1b042d1e27BF7B2bee000a23C59f9eB0aC6Fdce', 'topics': [ hexbytes.HexBytes( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4' @@ -50,29 +42,21 @@ '0x0000000000000000000000000000000000000000000000000000000' '000000000') ], - 'data': - '0x0000000000000000000000000000000000000000000000000000000' + 'data': '0x0000000000000000000000000000000000000000000000000000000' '0127a3980', - 'blockNumber': - 18862558, - 'transactionHash': - hexbytes.HexBytes( + 'blockNumber': 18862558, + 'transactionHash': hexbytes.HexBytes( '0xa34a0d63bac40ae34153483a5c69663c2b32e5e200c2e2460b189aed3f0' 'a76c9'), - 'transactionIndex': - 1, - 'blockHash': - hexbytes.HexBytes( + 'transactionIndex': 1, + 'blockHash': hexbytes.HexBytes( '0x24aa438ba5aa72634a09f77acefb5c8cce1261b44681e72488d4405e311' 'fa9a2'), - 'logIndex': - 0, - 'removed': - False + 'logIndex': 0, + 'removed': False }), web3.datastructures.AttributeDict({ - 'address': - '0xE1b042d1e27BF7B2bee000a23C59f9eB0aC6Fdce', + 'address': '0xE1b042d1e27BF7B2bee000a23C59f9eB0aC6Fdce', 'topics': [ hexbytes.HexBytes( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4' @@ -84,36 +68,27 @@ '0x000000000000000000000000aae34ec313a97265635b84964689285' '49cdd4ab7') ], - 'data': - '0x0000000000000000000000000000000000000000000000000000000' + 'data': '0x0000000000000000000000000000000000000000000000000000000' '008f0d180', - 'blockNumber': - 18862558, - 'transactionHash': - hexbytes.HexBytes( + 'blockNumber': 18862558, + 'transactionHash': hexbytes.HexBytes( '0xa34a0d63bac40ae34153483a5c69663c2b32e5e200c2e2460b189aed3f0' 'a76c9'), - 'transactionIndex': - 1, - 'blockHash': - hexbytes.HexBytes( + 'transactionIndex': 1, + 'blockHash': hexbytes.HexBytes( '0x24aa438ba5aa72634a09f77acefb5c8cce1261b44681e72488d4405e311' 'fa9a2'), - 'logIndex': - 1, - 'removed': - False + 'logIndex': 1, + 'removed': False }), web3.datastructures.AttributeDict({ - 'address': - '0x5FE61d63264390b748EF714B461f3BA8965F541D', + 'address': '0x5FE61d63264390b748EF714B461f3BA8965F541D', 'topics': [ hexbytes.HexBytes( '0xe2d69d9df6c1e740c72aecc4a0cd85eca27cbc5273ec079de974008' 'f492a9f8b') ], - 'data': - '0x0000000000000000000000000000000000000000000000000000000' + 'data': '0x0000000000000000000000000000000000000000000000000000000' '00000000000000000000000000000000000000000000000000000000000000000' '00000006000000000000000000000000707527eb76bad9099a302b2e33851e958' '7e30ed00000000000000000000000000000000000000000000000000000000000' @@ -128,26 +103,19 @@ '0000000000000000000000000000000000000000000000000000000000002a307' '84531623034326431653237424637423262656530303061323343353966396542' '306143364664636500000000000000000000000000000000000000000000', - 'blockNumber': - 18862558, - 'transactionHash': - hexbytes.HexBytes( + 'blockNumber': 18862558, + 'transactionHash': hexbytes.HexBytes( '0xa34a0d63bac40ae34153483a5c69663c2b32e5e200c2e2460b189aed3f0' 'a76c9'), - 'transactionIndex': - 1, - 'blockHash': - hexbytes.HexBytes( + 'transactionIndex': 1, + 'blockHash': hexbytes.HexBytes( '0x24aa438ba5aa72634a09f77acefb5c8cce1261b44681e72488d4405e311' 'fa9a2'), - 'logIndex': - 2, - 'removed': - False + 'logIndex': 2, + 'removed': False }) ], - 'logsBloom': - hexbytes.HexBytes( + 'logsBloom': hexbytes.HexBytes( '0x0000200000000000000000000000000000000000000000000040000020000000000' '000000000000000000000000000000000000000000000000020000000000000400040' '000000000000000800000000000000000000000000100000000000000000020002000' @@ -156,39 +124,26 @@ '000000000000000000400020000000000000000000000000200000000000000000000' '000000000000000000000000000000002000000000000000000000000000000000000' '0000001000000000000000000000000'), - 'status': - 1, - 'to': - '0x5FE61d63264390b748EF714B461f3BA8965F541D', - 'transactionHash': - hexbytes.HexBytes( + 'status': 1, + 'to': '0x5FE61d63264390b748EF714B461f3BA8965F541D', + 'transactionHash': hexbytes.HexBytes( '0xa34a0d63bac40ae34153483a5c69663c2b32e5e200c2e2460b189aed3f0a76c9'), - 'transactionIndex': - 1, - 'type': - '0x2' + 'transactionIndex': 1, + 'type': '0x2' }) _TRANSFER_TRANSACTION_RECEIPT = web3.datastructures.AttributeDict({ - 'blockHash': - hexbytes.HexBytes( + 'blockHash': hexbytes.HexBytes( '0x3171ae38d5b93610423636162f2e18f00e691616f31876fa90ba818d30e3588d'), - 'blockNumber': - 18862990, - 'contractAddress': - None, - 'cumulativeGasUsed': - 457893, - 'effectiveGasPrice': - 8000000000, - 'from': - '0xaAE34Ec313A97265635B8496468928549cdd4AB7', - 'gasUsed': - 97949, + 'blockNumber': 18862990, + 'contractAddress': None, + 'cumulativeGasUsed': 457893, + 'effectiveGasPrice': 8000000000, + 'from': '0xaAE34Ec313A97265635B8496468928549cdd4AB7', + 'gasUsed': 97949, 'logs': [ web3.datastructures.AttributeDict({ - 'address': - '0xE1b042d1e27BF7B2bee000a23C59f9eB0aC6Fdce', + 'address': '0xE1b042d1e27BF7B2bee000a23C59f9eB0aC6Fdce', 'topics': [ hexbytes.HexBytes( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4' @@ -200,29 +155,21 @@ '0x000000000000000000000000aae34ec313a97265635b84964689285' '49cdd4ab7') ], - 'data': - '0x0000000000000000000000000000000000000000000000000000000' + 'data': '0x0000000000000000000000000000000000000000000000000000000' '0127a3980', - 'blockNumber': - 18862990, - 'transactionHash': - hexbytes.HexBytes( + 'blockNumber': 18862990, + 'transactionHash': hexbytes.HexBytes( '0x5976353de3a0f9914a21cd3b49901bfc4c58630be6ccd87734e015d5015' '9eeba'), - 'transactionIndex': - 1, - 'blockHash': - hexbytes.HexBytes( + 'transactionIndex': 1, + 'blockHash': hexbytes.HexBytes( '0x3171ae38d5b93610423636162f2e18f00e691616f31876fa90ba818d30e' '3588d'), - 'logIndex': - 0, - 'removed': - False + 'logIndex': 0, + 'removed': False }), web3.datastructures.AttributeDict({ - 'address': - '0xE1b042d1e27BF7B2bee000a23C59f9eB0aC6Fdce', + 'address': '0xE1b042d1e27BF7B2bee000a23C59f9eB0aC6Fdce', 'topics': [ hexbytes.HexBytes( '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4' @@ -234,36 +181,27 @@ '0x000000000000000000000000aae34ec313a97265635b84964689285' '49cdd4ab7') ], - 'data': - '0x0000000000000000000000000000000000000000000000000000000' + 'data': '0x0000000000000000000000000000000000000000000000000000000' '002faf080', - 'blockNumber': - 18862990, - 'transactionHash': - hexbytes.HexBytes( + 'blockNumber': 18862990, + 'transactionHash': hexbytes.HexBytes( '0x5976353de3a0f9914a21cd3b49901bfc4c58630be6ccd87734e015d5015' '9eeba'), - 'transactionIndex': - 1, - 'blockHash': - hexbytes.HexBytes( + 'transactionIndex': 1, + 'blockHash': hexbytes.HexBytes( '0x3171ae38d5b93610423636162f2e18f00e691616f31876fa90ba818d30e' '3588d'), - 'logIndex': - 1, - 'removed': - False + 'logIndex': 1, + 'removed': False }), web3.datastructures.AttributeDict({ - 'address': - '0x5FE61d63264390b748EF714B461f3BA8965F541D', + 'address': '0x5FE61d63264390b748EF714B461f3BA8965F541D', 'topics': [ hexbytes.HexBytes( '0xc554ec28e750cd02386397060a6c443fb4ad8e987c8f874185a60f9' 'e08ccbaad') ], - 'data': - '0x0000000000000000000000000000000000000000000000000000000' + 'data': '0x0000000000000000000000000000000000000000000000000000000' '000000001000000000000000000000000707527eb76bad9099a302b2e' '33851e9587e30ed0000000000000000000000000aae34ec313a972656' '35b8496468928549cdd4ab7000000000000000000000000e1b042d1e2' @@ -271,26 +209,19 @@ '00000000000000000000000000000127a398000000000000000000000' '00000000000000000000000000000000000002faf0800000000000000' '00000000000aae34ec313a97265635b8496468928549cdd4ab7', - 'blockNumber': - 18862990, - 'transactionHash': - hexbytes.HexBytes( + 'blockNumber': 18862990, + 'transactionHash': hexbytes.HexBytes( '0x5976353de3a0f9914a21cd3b49901bfc4c58630be6ccd87734e015d5015' '9eeba'), - 'transactionIndex': - 1, - 'blockHash': - hexbytes.HexBytes( + 'transactionIndex': 1, + 'blockHash': hexbytes.HexBytes( '0x3171ae38d5b93610423636162f2e18f00e691616f31876fa90ba818d30e' '3588d'), - 'logIndex': - 2, - 'removed': - False + 'logIndex': 2, + 'removed': False }) ], - 'logsBloom': - hexbytes.HexBytes( + 'logsBloom': hexbytes.HexBytes( '0x0000200000000000000000000000000000400000000000000000000020000000000' '000000000000000000000000000000000000000000000000020000000000000400040' '000000000000000800000000000000010000000000100000000000000000000000000' @@ -299,17 +230,12 @@ '000000000000000000400000000000000000000000000000200000000000000000000' '000000000000000000000000000000000000000000000000000000000000000000000' '0000001000000000000000000000000'), - 'status': - 1, - 'to': - '0x5FE61d63264390b748EF714B461f3BA8965F541D', - 'transactionHash': - hexbytes.HexBytes( + 'status': 1, + 'to': '0x5FE61d63264390b748EF714B461f3BA8965F541D', + 'transactionHash': hexbytes.HexBytes( '0x5976353de3a0f9914a21cd3b49901bfc4c58630be6ccd87734e015d50159eeba'), - 'transactionIndex': - 1, - 'type': - '0x2' + 'transactionIndex': 1, + 'type': '0x2' }) _INVALID_SIGNATURE_ERROR = 'PantosForwarder: invalid signature' @@ -519,8 +445,7 @@ def ethereum_client(mock_get_blockchain_config, mock_get_blockchain_utilities, with unittest.mock.patch.object(BlockchainClient, '__init__', lambda self: None): with unittest.mock.patch.object( - EthereumClient, - '_EthereumClient__create_node_connections', + EthereumClient, '_EthereumClient__create_node_connections', return_value=node_connections): mock_get_blockchain_config.return_value = { 'private_key': _KEYSTORE_PATH, @@ -576,8 +501,7 @@ def test_is_node_registered_error(ethereum_client, mock_get_blockchain_config): ethereum_client.is_node_registered() -@unittest.mock.patch.object(EthereumClient, - 'is_valid_address', +@unittest.mock.patch.object(EthereumClient, 'is_valid_address', side_effect=web3.Web3.is_checksum_address) def test_is_valid_recipient_address_checksum_true(mock_is_valid_address, ethereum_client): @@ -589,8 +513,7 @@ def test_is_valid_recipient_address_checksum_true(mock_is_valid_address, assert is_recipient_address_correct is True -@unittest.mock.patch.object(EthereumClient, - 'is_valid_address', +@unittest.mock.patch.object(EthereumClient, 'is_valid_address', side_effect=web3.Web3.is_checksum_address) def test_is_valid_recipient_address_checksum_false(mock_is_valid_address, ethereum_client): @@ -602,8 +525,7 @@ def test_is_valid_recipient_address_checksum_false(mock_is_valid_address, assert is_recipient_address_correct is False -@unittest.mock.patch.object(EthereumClient, - 'is_valid_address', +@unittest.mock.patch.object(EthereumClient, 'is_valid_address', side_effect=web3.Web3.is_checksum_address) def test_is_valid_recipient_address_0_address_false(mock_is_valid_address, ethereum_client): @@ -639,8 +561,7 @@ def test_read_node_url_error(ethereum_client, mock_get_blockchain_config): @pytest.mark.parametrize('node_stake', [0, 1]) -@unittest.mock.patch.object(EthereumClient, - '_start_transaction_submission', +@unittest.mock.patch.object(EthereumClient, '_start_transaction_submission', return_value=uuid.uuid4()) def test_register_node_correct(mock_start_transaction_submission, node_stake, ethereum_client, mock_get_blockchain_config, @@ -667,8 +588,7 @@ def test_register_node_correct(mock_start_transaction_submission, node_stake, @pytest.mark.parametrize('node_stake', [0, 1]) -@unittest.mock.patch.object(EthereumClient, - '_start_transaction_submission', +@unittest.mock.patch.object(EthereumClient, '_start_transaction_submission', side_effect=EthereumUtilitiesError) def test_register_node_error(mock_start_transaction_submission, node_stake, ethereum_client, mock_get_blockchain_config, @@ -681,8 +601,7 @@ def test_register_node_error(mock_start_transaction_submission, node_stake, service_node_address) -@unittest.mock.patch.object(EthereumClient, - '_start_transaction_submission', +@unittest.mock.patch.object(EthereumClient, '_start_transaction_submission', return_value=uuid.uuid4()) def test_unregister_node_correct(mock_start_transaction_submission, ethereum_client, service_node_address): @@ -694,8 +613,7 @@ def test_unregister_node_correct(mock_start_transaction_submission, assert unregister_request.function_args == (service_node_address) -@unittest.mock.patch.object(EthereumClient, - '_start_transaction_submission', +@unittest.mock.patch.object(EthereumClient, '_start_transaction_submission', side_effect=EthereumUtilitiesError) def test_unregister_node_error(mock_start_transaction_submission, ethereum_client): @@ -703,8 +621,7 @@ def test_unregister_node_error(mock_start_transaction_submission, ethereum_client.unregister_node() -@unittest.mock.patch.object(EthereumClient, - '_start_transaction_submission', +@unittest.mock.patch.object(EthereumClient, '_start_transaction_submission', return_value=uuid.uuid4()) def test_update_node_url_correct(mock_start_transaction_submission, ethereum_client, service_node_url): @@ -716,8 +633,7 @@ def test_update_node_url_correct(mock_start_transaction_submission, assert update_request.function_args == (service_node_url, ) -@unittest.mock.patch.object(EthereumClient, - '_start_transaction_submission', +@unittest.mock.patch.object(EthereumClient, '_start_transaction_submission', side_effect=EthereumUtilitiesError) def test_update_node_url_error(mock_start_transaction_submission, ethereum_client, service_node_url): @@ -749,8 +665,7 @@ def test_start_transfer_submission_correct(mock_create_hub_contract, with unittest.mock.patch.object(ethereum_client._get_utilities(), 'start_transaction_submission', mock_start_transaction_submission): - with unittest.mock.patch.object(w3.eth, - 'get_transaction_count', + with unittest.mock.patch.object(w3.eth, 'get_transaction_count', return_value=blockchain_nonce): response_internal_transaction_id = ethereum_client.\ start_transfer_submission(transfer_submission_start_request) @@ -784,8 +699,7 @@ def test_start_transfer_from_submission_correct( with unittest.mock.patch.object(ethereum_client._get_utilities(), 'start_transaction_submission', mock_start_transaction_submission): - with unittest.mock.patch.object(w3.eth, - 'get_transaction_count', + with unittest.mock.patch.object(w3.eth, 'get_transaction_count', return_value=blockchain_nonce): response_internal_transaction_id = ethereum_client.\ start_transfer_from_submission( @@ -804,8 +718,7 @@ def test_start_transfer_submission_node_communication_error( transfer_submission_start_request): error_message = 'some blockchain node error message' - with unittest.mock.patch.object(w3.eth, - 'get_transaction_count', + with unittest.mock.patch.object(w3.eth, 'get_transaction_count', side_effect=Exception(error_message)): with pytest.raises(EthereumClientError) as exception_info: ethereum_client.start_transfer_submission( @@ -822,8 +735,7 @@ def test_start_transfer_from_submission_node_communication_error( transfer_from_submission_start_request): error_message = 'some blockchain node error message' - with unittest.mock.patch.object(w3.eth, - 'get_transaction_count', + with unittest.mock.patch.object(w3.eth, 'get_transaction_count', side_effect=Exception(error_message)): with pytest.raises(EthereumClientError) as exception_info: ethereum_client.start_transfer_from_submission( @@ -952,8 +864,7 @@ def test_read_on_chain_transfer_id_correct(mock_create_hub_contract, } } - with unittest.mock.patch.object(w3.eth, - 'get_transaction_receipt', + with unittest.mock.patch.object(w3.eth, 'get_transaction_receipt', return_value=transaction_receipt[0]): response_on_chain_transfer_id = \ ethereum_client._read_on_chain_transfer_id( @@ -968,8 +879,7 @@ def test_read_on_chain_transfer_id_error(mock_create_hub_contract, transaction_id = 'some_transaction_hash' destination_blockchain = Blockchain.CELO - with unittest.mock.patch.object(w3.eth, - 'get_transaction_receipt', + with unittest.mock.patch.object(w3.eth, 'get_transaction_receipt', side_effect=Exception): with pytest.raises(EthereumClientError) as exception_info: ethereum_client._read_on_chain_transfer_id(transaction_id, @@ -981,8 +891,7 @@ def test_read_on_chain_transfer_id_error(mock_create_hub_contract, @unittest.mock.patch.object(EthereumClient, '_get_utilities') -@unittest.mock.patch.object(EthereumClient, - '_get_config', +@unittest.mock.patch.object(EthereumClient, '_get_config', return_value={'provider_timeout': None}) @unittest.mock.patch.object(EthereumClient, '__init__', lambda *args: None) def test_create_web3_correct(mock_get_config, mock_get_utilities, @@ -1015,8 +924,7 @@ def test_is_unbonding_error(ethereum_client, mock_get_blockchain_config): ethereum_client.is_unbonding() -@unittest.mock.patch.object(EthereumClient, - '_start_transaction_submission', +@unittest.mock.patch.object(EthereumClient, '_start_transaction_submission', return_value=uuid.uuid4()) def test_cancel_unregistration_correct(mock_start_transaction_submission, ethereum_client, service_node_address): @@ -1028,8 +936,7 @@ def test_cancel_unregistration_correct(mock_start_transaction_submission, assert cancel_request.function_args == (service_node_address) -@unittest.mock.patch.object(EthereumClient, - '_start_transaction_submission', +@unittest.mock.patch.object(EthereumClient, '_start_transaction_submission', side_effect=EthereumUtilitiesError) def test_cancel_unregistration_error(mock_start_transaction_submission, ethereum_client): diff --git a/tests/business/test_bids.py b/tests/business/test_bids.py index 5cdc9fb..1420cbc 100644 --- a/tests/business/test_bids.py +++ b/tests/business/test_bids.py @@ -25,7 +25,6 @@ class Bid: class MockDatabaseAccess: - def create_bid(self, source_blockchain, destination_blockchain, execution_time, valid_until, fee): assert isinstance(source_blockchain, Blockchain) @@ -53,10 +52,7 @@ def bid_interactor(): return BidInteractor() -def generate_bids(blockchains, - number_bids, - only_active=True, - bid_id_offset=0, +def generate_bids(blockchains, number_bids, only_active=True, bid_id_offset=0, extra_fee=0): all_bids = {} all_blockchain_ids = [blockchain.value for blockchain in Blockchain] @@ -127,8 +123,7 @@ def test_get_cross_blockchain_bids_correct(mocked_get_signer, bid_interactor): @unittest.mock.patch( 'pantos.servicenode.business.bids.database_access.' - 'read_cross_blockchain_bids', - side_effect=BidInteractorError) + 'read_cross_blockchain_bids', side_effect=BidInteractorError) def test_get_cross_blockchain_bids_error(mocked_db_read, bid_interactor): with pytest.raises(BidInteractorError): bid_interactor.get_cross_blockchain_bids(0, 1) diff --git a/tests/business/test_node.py b/tests/business/test_node.py index e2d4b10..adf2040 100644 --- a/tests/business/test_node.py +++ b/tests/business/test_node.py @@ -21,13 +21,11 @@ class MockBlockchainClientError(BlockchainClientError): - def __init__(self): super().__init__('') class MockBlockchainClient: - def __init__(self, node_registered, is_unbonding, raise_error): self.node_registered = node_registered self.unbonding = is_unbonding diff --git a/tests/business/test_plugins.py b/tests/business/test_plugins.py index 7818f86..dac71c8 100644 --- a/tests/business/test_plugins.py +++ b/tests/business/test_plugins.py @@ -11,7 +11,6 @@ class MockedBidPlugin: - def __init__(self, raise_error=False): self.raise_error = raise_error diff --git a/tests/business/test_transfers.py b/tests/business/test_transfers.py index 929959a..d464f32 100644 --- a/tests/business/test_transfers.py +++ b/tests/business/test_transfers.py @@ -25,7 +25,6 @@ class MockBidPlugin: - def accept_bid(self, bid): return True @@ -385,8 +384,7 @@ def test_confirm_transfer_confirmed_correct(mocked_database_access, transaction_id, transfer_on_chain_id): status_response = BlockchainClient.TransferSubmissionStatusResponse( - True, - transaction_status=TransactionStatus.CONFIRMED, + True, transaction_status=TransactionStatus.CONFIRMED, transaction_id=transaction_id, on_chain_transfer_id=transfer_on_chain_id) mocked_get_blockchain_client().get_transfer_submission_status.\ @@ -441,8 +439,7 @@ def test_confirm_transfer_reverted_correct(mocked_database_access, confirm_transfer_request, transaction_id): status_response = BlockchainClient.TransferSubmissionStatusResponse( - True, - transaction_status=TransactionStatus.REVERTED, + True, transaction_status=TransactionStatus.REVERTED, transaction_id=transaction_id) mocked_get_blockchain_client().get_transfer_submission_status.\ return_value = status_response @@ -535,8 +532,7 @@ def test_execute_transfer_task_correct( @unittest.mock.patch('pantos.servicenode.business.transfers.config') @unittest.mock.patch.object( - TransferInteractor, - 'execute_transfer', + TransferInteractor, 'execute_transfer', side_effect=TransferInteractorUnrecoverableError('')) def test_execute_transfer_task_unrecoverable_error( mocked_execute_transfer, transfer_internal_id, source_blockchain, @@ -663,8 +659,7 @@ def test_confirm_transfer_task_confirmation_error( @unittest.mock.patch.object( - TransferInteractor, - '_TransferInteractor__is_valid_execution_time_limit', + TransferInteractor, '_TransferInteractor__is_valid_execution_time_limit', return_value=True) def test_check_valid_until_correct(mocked_is_valid_execution_time_limit, source_blockchain, valid_until, @@ -674,8 +669,7 @@ def test_check_valid_until_correct(mocked_is_valid_execution_time_limit, @unittest.mock.patch.object( - TransferInteractor, - '_TransferInteractor__is_valid_execution_time_limit', + TransferInteractor, '_TransferInteractor__is_valid_execution_time_limit', return_value=False) def test_check_valid_until_invalid(mocked_is_valid_execution_time_limit, source_blockchain, valid_until, diff --git a/tests/database/conftest.py b/tests/database/conftest.py index 67bb437..bed12f5 100644 --- a/tests/database/conftest.py +++ b/tests/database/conftest.py @@ -32,18 +32,14 @@ def populate_transfer_database(session, source_blockchain_ids, statuses, for source_blockchain_id, nonce, status in zip(source_blockchain_ids, nonces, statuses): transfer = Transfer(source_blockchain_id=source_blockchain_id, - destination_blockchain_id=0, - sender_address='', + destination_blockchain_id=0, sender_address='', recipient_address='', source_token_contract_id=token_contract.id, destination_token_contract_id=token_contract.id, - amount=0, - fee=0, - signature='', + amount=0, fee=0, signature='', hub_contract_id=hub_contract.id, forwarder_contract_id=forwarder_contract.id, - nonce=nonce, - status_id=status) + nonce=nonce, status_id=status) session.add(transfer) session.flush() transfer_ids.append(transfer.id) diff --git a/tests/database/sqlite/access/conftest.py b/tests/database/sqlite/access/conftest.py index f938295..9176e7b 100644 --- a/tests/database/sqlite/access/conftest.py +++ b/tests/database/sqlite/access/conftest.py @@ -54,8 +54,7 @@ def bid(source_blockchain_id, destination_blockchain_id, bid_execution_time, bid_valid_until, bid_fee): return Bid(source_blockchain_id=source_blockchain_id, destination_blockchain_id=destination_blockchain_id, - execution_time=bid_execution_time, - valid_until=bid_valid_until, + execution_time=bid_execution_time, valid_until=bid_valid_until, fee=bid_fee) @@ -146,22 +145,18 @@ def transfer(source_blockchain_id, destination_blockchain_id, transfer_signature, hub_contract, forwarder_contract, transfer_task_id, on_chain_transfer_id, transfer_status_id, transfer_transaction_id): - return Transfer(source_blockchain_id=source_blockchain_id, - destination_blockchain_id=destination_blockchain_id, - sender_address=transfer_sender_address, - recipient_address=transfer_recipient_address, - source_token_contract=source_token_contract, - destination_token_contract=destination_token_contract, - amount=transfer_amount, - fee=bid_fee, - sender_nonce=transfer_sender_nonce, - signature=transfer_signature, - hub_contract=hub_contract, - forwarder_contract=forwarder_contract, - task_id=transfer_task_id, - on_chain_transfer_id=on_chain_transfer_id, - status_id=transfer_status_id, - transaction_id=transfer_transaction_id) + return Transfer( + source_blockchain_id=source_blockchain_id, + destination_blockchain_id=destination_blockchain_id, + sender_address=transfer_sender_address, + recipient_address=transfer_recipient_address, + source_token_contract=source_token_contract, + destination_token_contract=destination_token_contract, + amount=transfer_amount, fee=bid_fee, + sender_nonce=transfer_sender_nonce, signature=transfer_signature, + hub_contract=hub_contract, forwarder_contract=forwarder_contract, + task_id=transfer_task_id, on_chain_transfer_id=on_chain_transfer_id, + status_id=transfer_status_id, transaction_id=transfer_transaction_id) @pytest.fixture(scope='module') diff --git a/tests/restapi/test_bids.py b/tests/restapi/test_bids.py index c6f0bf6..9c9f799 100644 --- a/tests/restapi/test_bids.py +++ b/tests/restapi/test_bids.py @@ -8,8 +8,7 @@ def test_bids_correct(bids, test_client): - with unittest.mock.patch.object(BidInteractor, - 'get_cross_blockchain_bids', + with unittest.mock.patch.object(BidInteractor, 'get_cross_blockchain_bids', return_value=bids): response = test_client.get( '/bids?source_blockchain=1&destination_blockchain=3') diff --git a/tests/restapi/test_transfer.py b/tests/restapi/test_transfer.py index 11afd75..a72a059 100644 --- a/tests/restapi/test_transfer.py +++ b/tests/restapi/test_transfer.py @@ -18,8 +18,7 @@ def test_transfer_correct(mocked_load, test_client, uuid_, initiate_transfer_request): mocked_load.return_value = initiate_transfer_request - with unittest.mock.patch.object(TransferInteractor, - 'initiate_transfer', + with unittest.mock.patch.object(TransferInteractor, 'initiate_transfer', return_value=uuid_): response = test_client.post('/transfer', json={}) @@ -28,8 +27,7 @@ def test_transfer_correct(mocked_load, test_client, uuid_, @unittest.mock.patch('pantos.servicenode.restapi.not_acceptable') -@unittest.mock.patch.object(_TransferSchema, - 'load', +@unittest.mock.patch.object(_TransferSchema, 'load', side_effect=marshmallow.ValidationError('')) def test_transfer_validation_error(mocked_load, mocked_not_acceptable, test_client): @@ -44,10 +42,9 @@ def test_transfer_validation_error(mocked_load, mocked_not_acceptable, @unittest.mock.patch('pantos.servicenode.restapi.conflict') -@unittest.mock.patch.object(TransferInteractor, - 'initiate_transfer', - side_effect=SenderNonceNotUniqueError( - Blockchain.ETHEREUM, '', 0)) +@unittest.mock.patch.object( + TransferInteractor, 'initiate_transfer', + side_effect=SenderNonceNotUniqueError(Blockchain.ETHEREUM, '', 0)) @unittest.mock.patch.object(_TransferSchema, 'load') def test_transfer_sender_nonce_not_unique_error(mocked_load, mocked_initiate_transfer, @@ -67,8 +64,7 @@ def test_transfer_sender_nonce_not_unique_error(mocked_load, @unittest.mock.patch('pantos.servicenode.restapi.not_acceptable') @unittest.mock.patch.object( - TransferInteractor, - 'initiate_transfer', + TransferInteractor, 'initiate_transfer', side_effect=TransferInteractorBidNotAcceptedError('bid not accepted')) @unittest.mock.patch.object(_TransferSchema, 'load') def test_transfer_bid_not_accepted_error(mocked_load, mocked_initiate_transfer, diff --git a/tests/restapi/test_transfer_status.py b/tests/restapi/test_transfer_status.py index eb28657..1bfe40f 100644 --- a/tests/restapi/test_transfer_status.py +++ b/tests/restapi/test_transfer_status.py @@ -48,8 +48,7 @@ def test_transfer_status_correct(mocked_load, mocked_find_transfer, @unittest.mock.patch( 'pantos.servicenode.restapi.resource_not_found', lambda error_message: flask_restful.abort(404, message=error_message)) -@unittest.mock.patch.object(_TransferStatusSchema, - 'load', +@unittest.mock.patch.object(_TransferStatusSchema, 'load', side_effect=marshmallow.ValidationError('')) def test_transfer_status_validation_error(mocked_load, test_client, uuid_): expected_error_messsage = f'task ID {uuid_} is not a UUID' @@ -79,8 +78,7 @@ def test_transfer_status_resource_not_found_error(mocked_load, @unittest.mock.patch('pantos.servicenode.restapi.internal_server_error', lambda error_message: flask_restful.abort(500)) -@unittest.mock.patch.object(_TransferStatusSchema, - 'load', +@unittest.mock.patch.object(_TransferStatusSchema, 'load', side_effect=Exception) def test_transfer_status_internal_error(mocked_load, test_client, uuid_): response = test_client.get(f'/transfer/{uuid_}/status') diff --git a/tests/test_application.py b/tests/test_application.py index ec096c7..7816ec3 100644 --- a/tests/test_application.py +++ b/tests/test_application.py @@ -178,8 +178,7 @@ def test_create_application_correct(mock_config, mock_flask_app, assert returned_flask_app == mock_flask_app -@unittest.mock.patch.object(NodeInteractor, - 'update_node_registrations', +@unittest.mock.patch.object(NodeInteractor, 'update_node_registrations', side_effect=Exception) @unittest.mock.patch('pantos.servicenode.application.initialize_application') @unittest.mock.patch('pantos.servicenode.restapi.flask_app')