diff --git a/pantos/validatornode/business/transfers.py b/pantos/validatornode/business/transfers.py index 776b32e..e341f0b 100644 --- a/pantos/validatornode/business/transfers.py +++ b/pantos/validatornode/business/transfers.py @@ -182,6 +182,9 @@ def detect_new_transfers(self, source_blockchain: Blockchain) -> None: if internal_transfer_id is None: _logger.info('new token transfer', extra=vars(found_transfer)) + # Secondary nodes also assign a validator nonce + # since they are supposed to be able to assume the + # primary role anytime after reconfiguration validator_nonce = self.__find_unused_validator_nonce( found_transfer.destination_blockchain) transfer_creation_request = TransferCreationRequest( @@ -259,6 +262,33 @@ def get_validator_nonce(self, source_blockchain: Blockchain, source_blockchain=source_blockchain, source_transaction_id=source_transaction_id) + def submit_transfer_to_primary_node(self, internal_transfer_id: int, + transfer: CrossChainTransfer) -> bool: + """Submit the signature for a cross-chain token transfer after + its successful validation to the primary validator node. + + Parameters + ---------- + internal_transfer_id : int + The unique internal ID of the transfer. + transfer : CrossChainTransfer + The data of the cross-chain token transfer to submit. + + Returns + ------- + bool + True if the submission is completed for the transfer. + + Raises + ------ + TransferInteractorError + If an error occurs during submitting the signature for a + cross-chain token transfer. + + """ + assert not self._is_primary_node() # pragma: no cover + raise NotImplementedError # pragma: no cover + def submit_transfer_onchain(self, internal_transfer_id: int, transfer: CrossChainTransfer) -> bool: """Submit a cross-chain token transfer after its successful @@ -406,7 +436,8 @@ def validate_transfer(self, internal_transfer_id: int, submit_transfer_onchain_task.delay(internal_transfer_id, transfer.to_dict()) else: - raise NotImplementedError # pragma: no cover + submit_transfer_to_primary_node_task.delay( + internal_transfer_id, transfer.to_dict()) return True except TransferInteractor.__TransferValidationError as error: return error.is_permanent() @@ -763,6 +794,49 @@ def confirm_transfer_task(self, internal_transfer_id: int, return True +@celery_app.task(bind=True, max_retries=None) +def submit_transfer_to_primary_node_task( + self, internal_transfer_id: int, + transfer_dict: CrossChainTransferDict) -> bool: + """Celery task for submitting the signature for a cross-chain token + transfer after its successful validation to the primary validator + node. + + Parameters + ---------- + internal_transfer_id : int + The unique internal ID of the transfer. + transfer_dict : CrossChainTransferDict + The data of the cross-chain token transfer to submit. + + Returns + ------- + bool + True if the task is executed without error. + + """ + transfer = CrossChainTransfer.from_dict(transfer_dict) + try: + submission_completed = \ + TransferInteractor().submit_transfer_to_primary_node( + internal_transfer_id, transfer) + except Exception as error: + _logger.error( + 'unable to submit the signature for a token transfer to the ' + 'primary validator node', extra=vars(transfer) | { + 'internal_transfer_id': internal_transfer_id, + 'task_id': self.request.id + }, exc_info=True) + retry_interval = config['tasks']['submit_transfer_to_primary_node'][ + 'retry_interval_after_error_in_seconds'] + raise self.retry(countdown=retry_interval, exc=error) + if not submission_completed: + retry_interval = config['tasks']['submit_transfer_to_primary_node'][ + 'retry_interval_in_seconds'] + raise self.retry(countdown=retry_interval) + return True + + @celery_app.task(bind=True, max_retries=None) def submit_transfer_onchain_task( self, internal_transfer_id: int, diff --git a/pantos/validatornode/configuration.py b/pantos/validatornode/configuration.py index 060553a..54aa4ed 100644 --- a/pantos/validatornode/configuration.py +++ b/pantos/validatornode/configuration.py @@ -275,8 +275,8 @@ 'required': True, 'schema': { 'confirm_transfer': _VALIDATION_SCHEMA_TASK, - 'submit_transfer_offchain': _VALIDATION_SCHEMA_TASK, 'submit_transfer_onchain': _VALIDATION_SCHEMA_TASK, + 'submit_transfer_to_primary_node': _VALIDATION_SCHEMA_TASK, 'validate_transfer': _VALIDATION_SCHEMA_TASK } }, diff --git a/pantos/validatornode/database/access.py b/pantos/validatornode/database/access.py index d5db74c..c473d1f 100644 --- a/pantos/validatornode/database/access.py +++ b/pantos/validatornode/database/access.py @@ -536,7 +536,7 @@ def update_reversal_transfer( destination_blockchain_id=destination_blockchain.value, recipient_address=recipient_address, destination_token_contract_id=destination_token_contract_id, - updated=datetime.datetime.utcnow()) + updated=datetime.datetime.now(datetime.timezone.utc)) session.execute(statement) @@ -564,7 +564,7 @@ def update_transfer_confirmed_destination_transaction( destination_transfer_id=destination_transfer_id, destination_transaction_id=destination_transaction_id, destination_block_number=destination_block_number, - updated=datetime.datetime.utcnow()) + updated=datetime.datetime.now(datetime.timezone.utc)) with get_session_maker().begin() as session: session.execute(statement) @@ -608,7 +608,7 @@ def update_transfer_submitted_destination_transaction( destination_hub_contract_id=destination_hub_contract_id, destination_forwarder_contract_id= # noqa: E251 destination_forwarder_contract_id, - updated=datetime.datetime.utcnow()) + updated=datetime.datetime.now(datetime.timezone.utc)) session.execute(update_statement) @@ -730,8 +730,8 @@ def update_transfer_source_transaction(internal_transfer_id: int, source_transfer_id) transfer.source_block_number = typing.cast(sqlalchemy.Column, source_block_number) - transfer.updated = typing.cast(sqlalchemy.Column, - datetime.datetime.utcnow()) + transfer.updated = typing.cast( + sqlalchemy.Column, datetime.datetime.now(datetime.timezone.utc)) def update_transfer_status(internal_transfer_id: int, @@ -750,8 +750,8 @@ def update_transfer_status(internal_transfer_id: int, transfer = session.get(Transfer, internal_transfer_id) assert transfer is not None transfer.status_id = typing.cast(sqlalchemy.Column, status.value) - transfer.updated = typing.cast(sqlalchemy.Column, - datetime.datetime.utcnow()) + transfer.updated = typing.cast( + sqlalchemy.Column, datetime.datetime.now(datetime.timezone.utc)) def update_transfer_task_id(internal_transfer_id: int, @@ -770,8 +770,28 @@ def update_transfer_task_id(internal_transfer_id: int, transfer = session.get(Transfer, internal_transfer_id) assert transfer is not None transfer.task_id = typing.cast(sqlalchemy.Column, str(task_id)) - transfer.updated = typing.cast(sqlalchemy.Column, - datetime.datetime.utcnow()) + transfer.updated = typing.cast( + sqlalchemy.Column, datetime.datetime.now(datetime.timezone.utc)) + + +def update_transfer_validator_nonce(internal_transfer_id: int, + validator_nonce: int) -> None: + """Update a transfer's validator nonce. + + Parameters + ---------- + internal_transfer_id : int + The unique internal ID of the transfer. + validator_nonce : int + The new validator nonce assigned to the transfer. + + """ + statement = sqlalchemy.update(Transfer).where( + Transfer.id == internal_transfer_id).values( + validator_nonce=validator_nonce, + updated=datetime.datetime.now(datetime.timezone.utc)) + with get_session_maker().begin() as session: + session.execute(statement) def _read_id(session: sqlalchemy.orm.Session, model: typing.Type[B], diff --git a/tests/business/transfers/test_submit_transfer_to_primary_node.py b/tests/business/transfers/test_submit_transfer_to_primary_node.py new file mode 100644 index 0000000..062adcb --- /dev/null +++ b/tests/business/transfers/test_submit_transfer_to_primary_node.py @@ -0,0 +1,58 @@ +import unittest.mock + +import celery.exceptions # type: ignore +import pytest + +from pantos.validatornode.business.transfers import TransferInteractorError +from pantos.validatornode.business.transfers import \ + submit_transfer_to_primary_node_task + + +@pytest.mark.parametrize('submission_completed', [True, False]) +@unittest.mock.patch( + 'pantos.validatornode.business.transfers.config', { + 'tasks': { + 'submit_transfer_to_primary_node': { + 'retry_interval_in_seconds': 120 + } + } + }) +@unittest.mock.patch( + 'pantos.validatornode.business.transfers.TransferInteractor') +def test_submit_transfer_to_primary_node_task_correct( + mock_transfer_interactor, submission_completed, internal_transfer_id, + cross_chain_transfer, cross_chain_transfer_dict): + mock_transfer_interactor().submit_transfer_to_primary_node.return_value = \ + submission_completed + if submission_completed: + submit_transfer_to_primary_node_task(internal_transfer_id, + cross_chain_transfer_dict) + else: + with pytest.raises(celery.exceptions.Retry): + submit_transfer_to_primary_node_task(internal_transfer_id, + cross_chain_transfer_dict) + mock_transfer_interactor().submit_transfer_to_primary_node.\ + assert_called_once_with(internal_transfer_id, cross_chain_transfer) + + +@unittest.mock.patch( + 'pantos.validatornode.business.transfers.config', { + 'tasks': { + 'submit_transfer_to_primary_node': { + 'retry_interval_after_error_in_seconds': 300 + } + } + }) +@unittest.mock.patch( + 'pantos.validatornode.business.transfers.TransferInteractor') +def test_submit_transfer_to_primary_node_task_error(mock_transfer_interactor, + internal_transfer_id, + cross_chain_transfer, + cross_chain_transfer_dict): + mock_transfer_interactor().submit_transfer_to_primary_node.side_effect = \ + TransferInteractorError('') + with pytest.raises(TransferInteractorError): + submit_transfer_to_primary_node_task(internal_transfer_id, + cross_chain_transfer_dict) + mock_transfer_interactor().submit_transfer_to_primary_node.\ + assert_called_once_with(internal_transfer_id, cross_chain_transfer) diff --git a/tests/business/transfers/test_validate_transfer.py b/tests/business/transfers/test_validate_transfer.py index 25c227b..f549b4d 100644 --- a/tests/business/transfers/test_validate_transfer.py +++ b/tests/business/transfers/test_validate_transfer.py @@ -15,21 +15,29 @@ @pytest.mark.parametrize('destination_token_active', [True, False]) @pytest.mark.parametrize('recipient_address_valid', [True, False]) @pytest.mark.parametrize('in_other_source_transaction', [True, False]) -@unittest.mock.patch('pantos.validatornode.business.base.config', - {'application': { - 'mode': 'primary' - }}) +@pytest.mark.parametrize('is_primary_node', [True, False]) +@unittest.mock.patch('pantos.validatornode.business.transfers.' + 'submit_transfer_to_primary_node_task') @unittest.mock.patch( 'pantos.validatornode.business.transfers.submit_transfer_onchain_task') @unittest.mock.patch('pantos.validatornode.business.transfers.database_access') @unittest.mock.patch( 'pantos.validatornode.business.transfers.get_blockchain_client') +@unittest.mock.patch('pantos.validatornode.business.base.config') def test_validate_transfer_confirmed_correct( - mock_get_blockchain_client, mock_database_access, - mock_submit_transfer_onchain_task, in_other_source_transaction, - recipient_address_valid, destination_token_active, - external_token_address_correct, token_decimals_correct, - transfer_interactor, internal_transfer_id, cross_chain_transfer): + mock_config, mock_get_blockchain_client, mock_database_access, + mock_submit_transfer_onchain_task, + mock_submit_transfer_to_primary_node_task, is_primary_node, + in_other_source_transaction, recipient_address_valid, + destination_token_active, external_token_address_correct, + token_decimals_correct, transfer_interactor, internal_transfer_id, + cross_chain_transfer): + mock_config_dict = { + 'application': { + 'mode': 'primary' if is_primary_node else 'secondary' + } + } + mock_config.__getitem__.side_effect = mock_config_dict.__getitem__ transfer_in_source_transaction = ( cross_chain_transfer if not in_other_source_transaction else dataclasses.replace( @@ -59,10 +67,19 @@ def test_validate_transfer_confirmed_correct( cross_chain_transfer.eventual_recipient_address, cross_chain_transfer.eventual_destination_token_address) mock_database_access.update_transfer_status.assert_not_called() - mock_submit_transfer_onchain_task.delay.assert_called_once_with( - internal_transfer_id, transfer_in_source_transaction.to_dict()) + if is_primary_node: + mock_submit_transfer_onchain_task.delay.assert_called_once_with( + internal_transfer_id, transfer_in_source_transaction.to_dict()) + mock_submit_transfer_to_primary_node_task.delay.assert_not_called() + else: + mock_submit_transfer_onchain_task.delay.assert_not_called() + mock_submit_transfer_to_primary_node_task.delay.\ + assert_called_once_with(internal_transfer_id, + transfer_in_source_transaction.to_dict()) +@unittest.mock.patch('pantos.validatornode.business.transfers.' + 'submit_transfer_to_primary_node_task') @unittest.mock.patch( 'pantos.validatornode.business.transfers.submit_transfer_onchain_task') @unittest.mock.patch('pantos.validatornode.business.transfers.database_access') @@ -70,7 +87,8 @@ def test_validate_transfer_confirmed_correct( 'pantos.validatornode.business.transfers.get_blockchain_client') def test_validate_transfer_unconfirmed_correct( mock_get_blockchain_client, mock_database_access, - mock_submit_transfer_onchain_task, transfer_interactor, + mock_submit_transfer_onchain_task, + mock_submit_transfer_to_primary_node_task, transfer_interactor, internal_transfer_id, cross_chain_transfer): _initialize_mock_blockchain_client(mock_get_blockchain_client, TransactionStatus.UNCONFIRMED, @@ -84,19 +102,21 @@ def test_validate_transfer_unconfirmed_correct( mock_database_access.update_reversal_transfer.assert_not_called() mock_database_access.update_transfer_status.assert_not_called() mock_submit_transfer_onchain_task.delay.assert_not_called() + mock_submit_transfer_to_primary_node_task.delay.assert_not_called() +@unittest.mock.patch('pantos.validatornode.business.transfers.' + 'submit_transfer_to_primary_node_task') @unittest.mock.patch( 'pantos.validatornode.business.transfers.submit_transfer_onchain_task') @unittest.mock.patch('pantos.validatornode.business.transfers.database_access') @unittest.mock.patch( 'pantos.validatornode.business.transfers.get_blockchain_client') -def test_validate_transfer_reverted_correct(mock_get_blockchain_client, - mock_database_access, - mock_submit_transfer_onchain_task, - transfer_interactor, - internal_transfer_id, - cross_chain_transfer): +def test_validate_transfer_reverted_correct( + mock_get_blockchain_client, mock_database_access, + mock_submit_transfer_onchain_task, + mock_submit_transfer_to_primary_node_task, transfer_interactor, + internal_transfer_id, cross_chain_transfer): _initialize_mock_blockchain_client(mock_get_blockchain_client, TransactionStatus.REVERTED, cross_chain_transfer, True, True, True, @@ -110,19 +130,21 @@ def test_validate_transfer_reverted_correct(mock_get_blockchain_client, mock_database_access.update_transfer_status.assert_called_once_with( internal_transfer_id, TransferStatus.SOURCE_TRANSACTION_REVERTED) mock_submit_transfer_onchain_task.delay.assert_not_called() + mock_submit_transfer_to_primary_node_task.delay.assert_not_called() +@unittest.mock.patch('pantos.validatornode.business.transfers.' + 'submit_transfer_to_primary_node_task') @unittest.mock.patch( 'pantos.validatornode.business.transfers.submit_transfer_onchain_task') @unittest.mock.patch('pantos.validatornode.business.transfers.database_access') @unittest.mock.patch( 'pantos.validatornode.business.transfers.get_blockchain_client') -def test_validate_transfer_invalid_correct(mock_get_blockchain_client, - mock_database_access, - mock_submit_transfer_onchain_task, - transfer_interactor, - internal_transfer_id, - cross_chain_transfer): +def test_validate_transfer_invalid_correct( + mock_get_blockchain_client, mock_database_access, + mock_submit_transfer_onchain_task, + mock_submit_transfer_to_primary_node_task, transfer_interactor, + internal_transfer_id, cross_chain_transfer): _initialize_mock_blockchain_client(mock_get_blockchain_client, TransactionStatus.CONFIRMED, cross_chain_transfer, True, False, True, @@ -136,8 +158,11 @@ def test_validate_transfer_invalid_correct(mock_get_blockchain_client, mock_database_access.update_transfer_status.assert_called_once_with( internal_transfer_id, TransferStatus.SOURCE_TRANSACTION_INVALID) mock_submit_transfer_onchain_task.delay.assert_not_called() + mock_submit_transfer_to_primary_node_task.delay.assert_not_called() +@unittest.mock.patch('pantos.validatornode.business.transfers.' + 'submit_transfer_to_primary_node_task') @unittest.mock.patch( 'pantos.validatornode.business.transfers.submit_transfer_onchain_task') @unittest.mock.patch('pantos.validatornode.business.transfers.database_access') @@ -145,7 +170,8 @@ def test_validate_transfer_invalid_correct(mock_get_blockchain_client, 'pantos.validatornode.business.transfers.get_blockchain_client') def test_validate_transfer_not_found_in_transaction_error( mock_get_blockchain_client, mock_database_access, - mock_submit_transfer_onchain_task, transfer_interactor, + mock_submit_transfer_onchain_task, + mock_submit_transfer_to_primary_node_task, transfer_interactor, internal_transfer_id, cross_chain_transfer): _initialize_mock_blockchain_client(mock_get_blockchain_client, TransactionStatus.CONFIRMED, None, True, @@ -161,19 +187,21 @@ def test_validate_transfer_not_found_in_transaction_error( mock_database_access.update_reversal_transfer.assert_not_called() mock_database_access.update_transfer_status.assert_not_called() mock_submit_transfer_onchain_task.delay.assert_not_called() + mock_submit_transfer_to_primary_node_task.delay.assert_not_called() +@unittest.mock.patch('pantos.validatornode.business.transfers.' + 'submit_transfer_to_primary_node_task') @unittest.mock.patch( 'pantos.validatornode.business.transfers.submit_transfer_onchain_task') @unittest.mock.patch('pantos.validatornode.business.transfers.database_access') @unittest.mock.patch( 'pantos.validatornode.business.transfers.get_blockchain_client') -def test_validate_transfer_other_error(mock_get_blockchain_client, - mock_database_access, - mock_submit_transfer_onchain_task, - transfer_interactor, - internal_transfer_id, - cross_chain_transfer): +def test_validate_transfer_other_error( + mock_get_blockchain_client, mock_database_access, + mock_submit_transfer_onchain_task, + mock_submit_transfer_to_primary_node_task, transfer_interactor, + internal_transfer_id, cross_chain_transfer): mock_get_blockchain_client.side_effect = Exception with pytest.raises(TransferInteractorError) as exception_info: @@ -186,6 +214,7 @@ def test_validate_transfer_other_error(mock_get_blockchain_client, mock_database_access.update_reversal_transfer.assert_not_called() mock_database_access.update_transfer_status.assert_not_called() mock_submit_transfer_onchain_task.delay.assert_not_called() + mock_submit_transfer_to_primary_node_task.delay.assert_not_called() @pytest.mark.parametrize('validation_completed', [True, False]) diff --git a/tests/database/sqlite/access/test_create_transfer.py b/tests/database/sqlite/access/test_create_transfer.py index 8e20774..5cf4193 100644 --- a/tests/database/sqlite/access/test_create_transfer.py +++ b/tests/database/sqlite/access/test_create_transfer.py @@ -127,5 +127,6 @@ def _check_created_transfer(created_transfer, input_transfer, TransferStatus.SOURCE_TRANSACTION_DETECTED.value) assert (created_transfer.status.name == TransferStatus.SOURCE_TRANSACTION_DETECTED.name) - assert created_transfer.created < datetime.datetime.utcnow() + assert created_transfer.created < datetime.datetime.now( + datetime.timezone.utc).replace(tzinfo=None) assert created_transfer.updated is None diff --git a/tests/database/sqlite/access/test_create_validator_node_signature.py b/tests/database/sqlite/access/test_create_validator_node_signature.py index 2a59350..6ba1ac3 100644 --- a/tests/database/sqlite/access/test_create_validator_node_signature.py +++ b/tests/database/sqlite/access/test_create_validator_node_signature.py @@ -36,4 +36,5 @@ def test_create_validator_node_signature_correct( if validator_node_existent: assert validator_node_signature.validator_node_id == validator_node.id assert validator_node_signature.signature == signature - assert validator_node_signature.created < datetime.datetime.utcnow() + assert validator_node_signature.created < datetime.datetime.now( + datetime.timezone.utc).replace(tzinfo=None) diff --git a/tests/database/sqlite/access/test_update_transfer_validator_nonce.py b/tests/database/sqlite/access/test_update_transfer_validator_nonce.py new file mode 100644 index 0000000..e9f6a93 --- /dev/null +++ b/tests/database/sqlite/access/test_update_transfer_validator_nonce.py @@ -0,0 +1,35 @@ +import datetime +import unittest.mock + +import sqlalchemy.orm + +from pantos.validatornode.database.access import \ + update_transfer_validator_nonce + + +@unittest.mock.patch('pantos.validatornode.database.access.get_session_maker') +def test_update_transfer_validator_nonce_correct( + mock_get_session_maker, initialized_database_session_maker, transfer, + other_validator_nonce): + assert transfer.validator_nonce != other_validator_nonce + mock_get_session_maker.return_value = initialized_database_session_maker + initialized_database_session = initialized_database_session_maker() + initialized_database_session.add(transfer) + initialized_database_session.commit() + transfer_dict = { + key: value + for key, value in vars(transfer).items() if key != 'validator_nonce' + and not isinstance(value, sqlalchemy.orm.state.InstanceState) + } + date_time_before_update = datetime.datetime.now(datetime.timezone.utc) + + update_transfer_validator_nonce(transfer.id, other_validator_nonce) + + date_time_after_update = datetime.datetime.now(datetime.timezone.utc) + initialized_database_session.refresh(transfer) + assert transfer.validator_nonce == other_validator_nonce + assert transfer.updated > date_time_before_update.replace(tzinfo=None) + assert transfer.updated < date_time_after_update.replace(tzinfo=None) + updated_transfer_dict = vars(transfer) + for key, value in transfer_dict.items(): + assert updated_transfer_dict[key] == value diff --git a/tests/test_configuration.py b/tests/test_configuration.py index f7e89b1..1f3bde8 100644 --- a/tests/test_configuration.py +++ b/tests/test_configuration.py @@ -59,10 +59,10 @@ confirm_transfer: retry_interval_in_seconds: 60 retry_interval_after_error_in_seconds: 300 - submit_transfer_offchain: + submit_transfer_onchain: retry_interval_in_seconds: 60 retry_interval_after_error_in_seconds: 300 - submit_transfer_onchain: + submit_transfer_to_primary_node: retry_interval_in_seconds: 60 retry_interval_after_error_in_seconds: 300 validate_transfer: diff --git a/validator-node-config.env b/validator-node-config.env index f4f6f66..cc2f14e 100644 --- a/validator-node-config.env +++ b/validator-node-config.env @@ -43,12 +43,12 @@ CELERY_BACKEND=db+postgresql://pantos-validator-node:${DATABASE_PASSWORD}@localh ##### Section: confirm_transfer ##### # TASKS_CONFIRM_TRANSFER_INTERVAL= # TASKS_CONFIRM_TRANSFER_RETRY_INTERVAL_AFTER_ERROR= -##### Section: submit_transfer_offchain ##### -# TASKS_SUBMIT_TRANSFER_OFFCHAIN_RETRY_INTERVAL= -# TASKS_SUBMIT_TRANSFER_OFFCHAIN_RETRY_INTERVAL_AFTER_ERROR= ##### Section: submit_transfer_onchain ##### # TASKS_SUBMIT_TRANSFER_ONCHAIN_RETRY_INTERVAL= # TASKS_SUBMIT_TRANSFER_ONCHAIN_RETRY_INTERVAL_AFTER_ERROR= +##### Section: submit_transfer_to_primary_node ##### +# TASKS_SUBMIT_TRANSFER_TO_PRIMARY_NODE_RETRY_INTERVAL= +# TASKS_SUBMIT_TRANSFER_TO_PRIMARY_NODE_RETRY_INTERVAL_AFTER_ERROR= ##### Section: validate_transfer ##### # TASKS_VALIDATE_TRANSFER_RETRY_INTERVAL= # TASKS_VALIDATE_TRANSFER_RETRY_INTERVAL_AFTER_ERROR= diff --git a/validator-node-config.yml b/validator-node-config.yml index 8d76371..2dd1742 100644 --- a/validator-node-config.yml +++ b/validator-node-config.yml @@ -43,12 +43,12 @@ tasks: confirm_transfer: retry_interval_in_seconds: !ENV tag:yaml.org,2002:int ${TASKS_CONFIRM_TRANSFER_RETRY_INTERVAL:60} retry_interval_after_error_in_seconds: !ENV tag:yaml.org,2002:int ${TASKS_CONFIRM_TRANSFER_RETRY_INTERVAL_AFTER_ERROR:300} - submit_transfer_offchain: - retry_interval_in_seconds: !ENV tag:yaml.org,2002:int ${TASKS_SUBMIT_TRANSFER_OFFCHAIN_RETRY_INTERVAL:60} - retry_interval_after_error_in_seconds: !ENV tag:yaml.org,2002:int ${TASKS_SUBMIT_TRANSFER_OFFCHAIN_RETRY_INTERVAL_AFTER_ERROR:300} submit_transfer_onchain: retry_interval_in_seconds: !ENV tag:yaml.org,2002:int ${TASKS_SUBMIT_TRANSFER_ONCHAIN_RETRY_INTERVAL:60} retry_interval_after_error_in_seconds: !ENV tag:yaml.org,2002:int ${TASKS_SUBMIT_TRANSFER_ONCHAIN_RETRY_INTERVAL_AFTER_ERROR:300} + submit_transfer_to_primary_node: + retry_interval_in_seconds: !ENV tag:yaml.org,2002:int ${TASKS_SUBMIT_TRANSFER_TO_PRIMARY_NODE_RETRY_INTERVAL:60} + retry_interval_after_error_in_seconds: !ENV tag:yaml.org,2002:int ${TASKS_SUBMIT_TRANSFER_TO_PRIMARY_NODE_RETRY_INTERVAL_AFTER_ERROR:300} validate_transfer: retry_interval_in_seconds: !ENV tag:yaml.org,2002:int ${TASKS_VALIDATE_TRANSFER_RETRY_INTERVAL:60} retry_interval_after_error_in_seconds: !ENV tag:yaml.org,2002:int ${TASKS_VALIDATE_TRANSFER_RETRY_INTERVAL_AFTER_ERROR:300}