Skip to content

packages.valory.skills.transaction_settlement_abci.tests.test_behaviours

Tests for valory/registration_abci skill's behaviours.

mock_yield_and_return

def mock_yield_and_return(
        return_value: Any) -> Callable[[], Generator[None, None, Any]]

Wrapper for a Dummy generator that returns a bool.

test_skill_public_id

def test_skill_public_id() -> None

Test skill module public ID

TransactionSettlementFSMBehaviourBaseCase Objects

class TransactionSettlementFSMBehaviourBaseCase(FSMBehaviourBaseCase)

Base case for testing TransactionSettlement FSMBehaviour.

ffw_signature

def ffw_signature(db_items: Optional[Dict] = None) -> None

Fast-forward to the SignatureBehaviour.

TestTransactionSettlementBaseBehaviour Objects

class TestTransactionSettlementBaseBehaviour(
        TransactionSettlementFSMBehaviourBaseCase)

Test TransactionSettlementBaseBehaviour.

test__get_tx_data

@pytest.mark.parametrize(
    "message, tx_digest, rpc_status, expected_data, replacement",
    (
        (
            MagicMock(performative=ContractApiMessage.Performative.ERROR,
                      message="GS026"),
            None,
            RPCResponseStatus.SUCCESS,
            {
                "blacklisted_keepers": set(),
                "keeper_retries": 2,
                "keepers": deque(("agent_1" + "-" * 35, "agent_3" + "-" * 35)),
                "status": VerificationStatus.VERIFIED,
                "tx_digest": "",
            },
            False,
        ),
        (
            MagicMock(performative=ContractApiMessage.Performative.ERROR,
                      message="test"),
            None,
            RPCResponseStatus.SUCCESS,
            {
                "blacklisted_keepers": set(),
                "keeper_retries": 2,
                "keepers": deque(("agent_1" + "-" * 35, "agent_3" + "-" * 35)),
                "status": VerificationStatus.ERROR,
                "tx_digest": "",
            },
            False,
        ),
        (
            MagicMock(
                performative=ContractApiMessage.Performative.RAW_MESSAGE),
            None,
            RPCResponseStatus.SUCCESS,
            {
                "blacklisted_keepers": set(),
                "keeper_retries": 2,
                "keepers": deque(("agent_1" + "-" * 35, "agent_3" + "-" * 35)),
                "status": VerificationStatus.PENDING,
                "tx_digest": "",
            },
            False,
        ),
        (
            MagicMock(
                performative=ContractApiMessage.Performative.RAW_TRANSACTION),
            None,
            RPCResponseStatus.INCORRECT_NONCE,
            {
                "blacklisted_keepers": set(),
                "keeper_retries": 2,
                "keepers": deque(("agent_1" + "-" * 35, "agent_3" + "-" * 35)),
                "status": VerificationStatus.ERROR,
                "tx_digest": "",
            },
            False,
        ),
        (
            MagicMock(
                performative=ContractApiMessage.Performative.RAW_TRANSACTION),
            None,
            RPCResponseStatus.INSUFFICIENT_FUNDS,
            {
                "blacklisted_keepers": {"agent_1" + "-" * 35},
                "keeper_retries": 1,
                "keepers": deque(("agent_3" + "-" * 35, )),
                "status": VerificationStatus.INSUFFICIENT_FUNDS,
                "tx_digest": "",
            },
            False,
        ),
        (
            MagicMock(
                performative=ContractApiMessage.Performative.RAW_TRANSACTION),
            None,
            RPCResponseStatus.UNCLASSIFIED_ERROR,
            {
                "blacklisted_keepers": set(),
                "keeper_retries": 2,
                "keepers": deque(("agent_1" + "-" * 35, "agent_3" + "-" * 35)),
                "status": VerificationStatus.PENDING,
                "tx_digest": "",
            },
            False,
        ),
        (
            MagicMock(
                performative=ContractApiMessage.Performative.RAW_TRANSACTION),
            None,
            RPCResponseStatus.UNDERPRICED,
            {
                "blacklisted_keepers": set(),
                "keeper_retries": 2,
                "keepers": deque(("agent_1" + "-" * 35, "agent_3" + "-" * 35)),
                "status": VerificationStatus.PENDING,
                "tx_digest": "",
            },
            False,
        ),
        (
            MagicMock(
                performative=ContractApiMessage.Performative.RAW_TRANSACTION),
            "test_digest_0",
            RPCResponseStatus.ALREADY_KNOWN,
            {
                "blacklisted_keepers": set(),
                "keeper_retries": 2,
                "keepers": deque(("agent_1" + "-" * 35, "agent_3" + "-" * 35)),
                "status": VerificationStatus.PENDING,
                "tx_digest": "test_digest_0",
            },
            False,
        ),
        (
            MagicMock(
                performative=ContractApiMessage.Performative.RAW_TRANSACTION,
                raw_transaction=MagicMock(
                    body={
                        "nonce": 0,
                        "maxPriorityFeePerGas": 10,
                        "maxFeePerGas": 20,
                        "gas": 0,
                    }),
            ),
            "test_digest_1",
            RPCResponseStatus.SUCCESS,
            {
                "blacklisted_keepers": set(),
                "keeper_retries": 2,
                "keepers": deque(("agent_1" + "-" * 35, "agent_3" + "-" * 35)),
                "status": VerificationStatus.PENDING,
                "tx_digest": "test_digest_1",
            },
            False,
        ),
        (
            MagicMock(
                performative=ContractApiMessage.Performative.RAW_TRANSACTION,
                raw_transaction=MagicMock(
                    body={
                        "nonce": 0,
                        "maxPriorityFeePerGas": 10,
                        "maxFeePerGas": 20,
                        "gas": 0,
                    }),
            ),
            "test_digest_2",
            RPCResponseStatus.SUCCESS,
            {
                "blacklisted_keepers": set(),
                "keeper_retries": 2,
                "keepers": deque(("agent_1" + "-" * 35, "agent_3" + "-" * 35)),
                "status": VerificationStatus.PENDING,
                "tx_digest": "test_digest_2",
            },
            True,
        ),
    ),
)
def test__get_tx_data(message: ContractApiMessage, tx_digest: Optional[str],
                      rpc_status: RPCResponseStatus, expected_data: TxDataType,
                      replacement: bool, monkeypatch: MonkeyPatch) -> None

Test _get_tx_data.

test_get_gas_price_params

@pytest.mark.parametrize(
    argnames=["tx_body", "expected_params"],
    argvalues=[
        [
            {
                "maxPriorityFeePerGas": "dummy",
                "maxFeePerGas": "dummy"
            },
            ["maxPriorityFeePerGas", "maxFeePerGas"],
        ],
        [{
            "gasPrice": "dummy"
        }, ["gasPrice"]],
        [
            {
                "maxPriorityFeePerGas": "dummy"
            },
            [],
        ],
        [
            {
                "maxFeePerGas": "dummy"
            },
            [],
        ],
        [
            {},
            [],
        ],
        [
            {
                "maxPriorityFeePerGas": "dummy",
                "maxFeePerGas": "dummy",
                "gasPrice": "dummy",
            },
            ["maxPriorityFeePerGas", "maxFeePerGas"],
        ],
    ],
)
def test_get_gas_price_params(tx_body: dict,
                              expected_params: List[str]) -> None

Test the get_gas_price_params method

test_parse_revert_reason_successful

def test_parse_revert_reason_successful() -> None

Test _parse_revert_reason method.

test_parse_revert_reason_unsuccessful

@pytest.mark.parametrize(
    "message",
    (
        MagicMock(
            performative=ContractApiMessage.Performative.ERROR,
            message="Non existing code should be invalid GS086.",
        ),
        MagicMock(
            performative=ContractApiMessage.Performative.ERROR,
            message="Code not matching the regex should be invalid GS0265.",
        ),
        MagicMock(
            performative=ContractApiMessage.Performative.ERROR,
            message="No code in the message should be invalid.",
        ),
        MagicMock(
            performative=ContractApiMessage.Performative.ERROR,
            message="",  # empty message should be invalid
        ),
        MagicMock(
            performative=ContractApiMessage.Performative.ERROR,
            message=None,  # `None` message should be invalid
        ),
    ),
)
def test_parse_revert_reason_unsuccessful(message: ContractApiMessage) -> None

Test _parse_revert_reason method.

TestRandomnessInOperation Objects

class TestRandomnessInOperation(BaseRandomnessBehaviourTest)

Test randomness in operation.

TestSelectKeeperTransactionSubmissionBehaviourA Objects

class TestSelectKeeperTransactionSubmissionBehaviourA(
        BaseSelectKeeperBehaviourTest)

Test SelectKeeperBehaviour.

TestSelectKeeperTransactionSubmissionBehaviourB Objects

class TestSelectKeeperTransactionSubmissionBehaviourB(
        TestSelectKeeperTransactionSubmissionBehaviourA)

Test SelectKeeperBehaviour.

test_select_keeper

@mock.patch.object(
    TransactionSettlementSynchronizedSata,
    "keepers",
    new_callable=mock.PropertyMock,
)
@mock.patch.object(
    TransactionSettlementSynchronizedSata,
    "keeper_retries",
    new_callable=mock.PropertyMock,
)
@mock.patch.object(
    TransactionSettlementSynchronizedSata,
    "final_verification_status",
    new_callable=mock.PropertyMock,
)
@pytest.mark.parametrize(
    "keepers, keeper_retries, blacklisted_keepers, final_verification_status",
    (
        (
            deque(f"keeper_{i}" for i in range(4)),
            1,
            set(),
            VerificationStatus.NOT_VERIFIED,
        ),
        (deque(("test_keeper", )), 2, set(), VerificationStatus.PENDING),
        (deque(("test_keeper", )), 2, set(), VerificationStatus.NOT_VERIFIED),
        (deque(("test_keeper", )), 2, {"a1"}, VerificationStatus.NOT_VERIFIED),
        (
            deque(("test_keeper", )),
            2,
            {"test_keeper"},
            VerificationStatus.NOT_VERIFIED,
        ),
        (
            deque(("test_keeper", )),
            2,
            {"a_1", "a_2", "test_keeper"},
            VerificationStatus.NOT_VERIFIED,
        ),
        (deque(("test_keeper", )), 1, set(), VerificationStatus.NOT_VERIFIED),
        (deque(("test_keeper", )), 3, set(), VerificationStatus.NOT_VERIFIED),
    ),
)
def test_select_keeper(final_verification_status_mock: mock.PropertyMock,
                       keeper_retries_mock: mock.PropertyMock,
                       keepers_mock: mock.PropertyMock, keepers: Deque[str],
                       keeper_retries: int, blacklisted_keepers: Set[str],
                       final_verification_status: VerificationStatus) -> None

Test select keeper agent.

test_select_keeper_tx_pending

@mock.patch.object(
    TransactionSettlementSynchronizedSata,
    "final_verification_status",
    new_callable=mock.PropertyMock,
    return_value=VerificationStatus.PENDING,
)
@pytest.mark.skip
def test_select_keeper_tx_pending(_: mock.PropertyMock,
                                  caplog: LogCaptureFixture) -> None

Test select keeper while tx is pending

TestSignatureBehaviour Objects

class TestSignatureBehaviour(TransactionSettlementFSMBehaviourBaseCase)

Test SignatureBehaviour.

test_signature_behaviour

def test_signature_behaviour() -> None

Test signature behaviour.

TestFinalizeBehaviour Objects

class TestFinalizeBehaviour(TransactionSettlementFSMBehaviourBaseCase)

Test FinalizeBehaviour.

test_non_sender_act

def test_non_sender_act() -> None

Test finalize behaviour.

test_sender_act

@pytest.mark.parametrize(
    "resubmitting, response_kwargs",
    (
        ((
            True,
            dict(
                performative=ContractApiMessage.Performative.RAW_TRANSACTION,
                callable="get_deploy_transaction",
                raw_transaction=RawTransaction(
                    ledger_id="ethereum",
                    body={
                        "tx_hash": "0x3b",
                        "nonce": 0,
                        "maxFeePerGas": int(10e10),
                        "maxPriorityFeePerGas": int(10e10),
                    },
                ),
            ),
        )),
        (
            False,
            dict(
                performative=ContractApiMessage.Performative.RAW_TRANSACTION,
                callable="get_deploy_transaction",
                raw_transaction=RawTransaction(
                    ledger_id="ethereum",
                    body={
                        "tx_hash": "0x3b",
                        "nonce": 0,
                        "maxFeePerGas": int(10e10),
                        "maxPriorityFeePerGas": int(10e10),
                    },
                ),
            ),
        ),
        (
            False,
            dict(
                performative=ContractApiMessage.Performative.ERROR,
                callable="get_deploy_transaction",
                code=500,
                message="GS026",
                data=b"",
            ),
        ),
        (
            False,
            dict(
                performative=ContractApiMessage.Performative.ERROR,
                callable="get_deploy_transaction",
                code=500,
                message="other error",
                data=b"",
            ),
        ),
    ),
)
@mock.patch.object(SkillContext,
                   "agent_address",
                   new_callable=mock.PropertyMock)
def test_sender_act(
    agent_address_mock: mock.PropertyMock, resubmitting: bool,
    response_kwargs: Dict[
        str,
        Union[
            int,
            str,
            bytes,
            Dict[str, Union[int, str]],
            ContractApiMessage.Performative,
            RawTransaction,
        ],
    ]
) -> None

Test finalize behaviour.

test_sender_act_tx_data_contains_tx_digest

def test_sender_act_tx_data_contains_tx_digest() -> None

Test finalize behaviour.

test_handle_late_messages

def test_handle_late_messages() -> None

Test handle_late_messages.

TestValidateTransactionBehaviour Objects

class TestValidateTransactionBehaviour(
        TransactionSettlementFSMBehaviourBaseCase)

Test ValidateTransactionBehaviour.

test_validate_transaction_safe_behaviour

def test_validate_transaction_safe_behaviour() -> None

Test ValidateTransactionBehaviour.

test_validate_transaction_safe_behaviour_no_tx_sent

def test_validate_transaction_safe_behaviour_no_tx_sent() -> None

Test ValidateTransactionBehaviour when tx cannot be sent.

TestCheckTransactionHistoryBehaviour Objects

class TestCheckTransactionHistoryBehaviour(
        TransactionSettlementFSMBehaviourBaseCase)

Test CheckTransactionHistoryBehaviour.

test_check_tx_history_behaviour

@pytest.mark.parametrize(
    "verified, status, hashes_history, revert_reason",
    (
        (False, -1, "0x" + "t" * 64, "test"),
        (False, 0, "", "test"),
        (False, 0, "0x" + "t" * 64, "test"),
        (False, 0, "0x" + "t" * 64, "GS026"),
        (True, 1, "0x" + "t" * 64, "test"),
    ),
)
def test_check_tx_history_behaviour(verified: bool, status: int,
                                    hashes_history: str,
                                    revert_reason: str) -> None

Test CheckTransactionHistoryBehaviour.

test_check_tx_history_behaviour_negative

@pytest.mark.parametrize(
    "verified, status, hashes_history, revert_reason",
    ((False, 0, "0x" + "t" * 64, "test"), ),
)
def test_check_tx_history_behaviour_negative(verified: bool, status: int,
                                             hashes_history: str,
                                             revert_reason: str) -> None

Test CheckTransactionHistoryBehaviour.

TestCheckLateTxHashesBehaviour Objects

class TestCheckLateTxHashesBehaviour(TransactionSettlementFSMBehaviourBaseCase
                                     )

Test CheckLateTxHashesBehaviour.

test_check_tx_history_behaviour

def test_check_tx_history_behaviour() -> None

Test CheckTransactionHistoryBehaviour.

TestSynchronizeLateMessagesBehaviour Objects

class TestSynchronizeLateMessagesBehaviour(
        TransactionSettlementFSMBehaviourBaseCase)

Test SynchronizeLateMessagesBehaviour

test_async_act

@pytest.mark.parametrize("late_messages", ([], [MagicMock, MagicMock]))
def test_async_act(late_messages: List[MagicMock]) -> None

Test async_act

test_short_circuit_clears_nondefault_late_messages

def test_short_circuit_clears_nondefault_late_messages() -> None

Short-circuit must reset a pre-existing non-default late_messages.

With a non-empty late_messages going in plus a dummy _get_tx_data that returns an empty tx_digest, the local _tx_hashes accumulator stays empty after the iterator drains. That triggers the short-circuit, and the assertion below catches any regression that drops the late_messages = [] reset.

TestResetBehaviour Objects

class TestResetBehaviour(TransactionSettlementFSMBehaviourBaseCase)

Test the reset behaviour.

test_reset_behaviour

def test_reset_behaviour() -> None

Test reset behaviour.