iwa 0.0.18__py3-none-any.whl → 0.0.20__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- iwa/core/chainlist.py +116 -0
- iwa/core/constants.py +1 -0
- iwa/core/contracts/cache.py +131 -0
- iwa/core/contracts/contract.py +7 -0
- iwa/core/rpc_monitor.py +60 -0
- iwa/plugins/olas/constants.py +41 -39
- iwa/plugins/olas/contracts/abis/mech_marketplace_v1.json +828 -0
- iwa/plugins/olas/contracts/activity_checker.py +63 -25
- iwa/plugins/olas/contracts/mech_marketplace_v1.py +68 -0
- iwa/plugins/olas/contracts/staking.py +115 -19
- iwa/plugins/olas/events.py +141 -0
- iwa/plugins/olas/scripts/test_full_mech_flow.py +1 -1
- iwa/plugins/olas/service_manager/base.py +7 -2
- iwa/plugins/olas/service_manager/lifecycle.py +30 -5
- iwa/plugins/olas/service_manager/mech.py +251 -42
- iwa/plugins/olas/service_manager/staking.py +6 -2
- iwa/plugins/olas/tests/test_olas_integration.py +38 -10
- iwa/plugins/olas/tests/test_service_manager.py +7 -1
- iwa/plugins/olas/tests/test_service_manager_errors.py +22 -11
- iwa/plugins/olas/tests/test_service_manager_flows.py +24 -8
- iwa/plugins/olas/tests/test_service_staking.py +59 -15
- iwa/plugins/olas/tests/test_staking_validation.py +8 -14
- iwa/tools/reset_tenderly.py +2 -2
- iwa/tools/test_chainlist.py +38 -0
- iwa/web/routers/olas/staking.py +9 -4
- {iwa-0.0.18.dist-info → iwa-0.0.20.dist-info}/METADATA +1 -1
- {iwa-0.0.18.dist-info → iwa-0.0.20.dist-info}/RECORD +32 -24
- tests/test_rpc_efficiency.py +103 -0
- {iwa-0.0.18.dist-info → iwa-0.0.20.dist-info}/WHEEL +0 -0
- {iwa-0.0.18.dist-info → iwa-0.0.20.dist-info}/entry_points.txt +0 -0
- {iwa-0.0.18.dist-info → iwa-0.0.20.dist-info}/licenses/LICENSE +0 -0
- {iwa-0.0.18.dist-info → iwa-0.0.20.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
from unittest.mock import MagicMock, patch
|
|
2
|
+
|
|
3
|
+
import pytest
|
|
4
|
+
|
|
5
|
+
from iwa.core.contracts.cache import ContractCache
|
|
6
|
+
from iwa.plugins.olas.contracts.staking import StakingContract
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@pytest.fixture
|
|
10
|
+
def mock_chain_interface():
|
|
11
|
+
with patch("iwa.core.contracts.contract.ChainInterfaces") as mock_chains:
|
|
12
|
+
mock_interface = MagicMock()
|
|
13
|
+
mock_chains.return_value.get.return_value = mock_interface
|
|
14
|
+
|
|
15
|
+
# Mock web3 and contract
|
|
16
|
+
mock_web3_backend = MagicMock()
|
|
17
|
+
mock_interface.web3._web3 = mock_web3_backend
|
|
18
|
+
|
|
19
|
+
mock_contract = MagicMock()
|
|
20
|
+
mock_web3_backend.eth.contract.return_value = mock_contract
|
|
21
|
+
|
|
22
|
+
# Mock with_retry to execute the function
|
|
23
|
+
mock_interface.with_retry.side_effect = lambda func, **kwargs: func()
|
|
24
|
+
|
|
25
|
+
# Yield both interface and contract mock
|
|
26
|
+
yield mock_interface, mock_contract
|
|
27
|
+
|
|
28
|
+
def test_staking_contract_lazy_loading(mock_chain_interface):
|
|
29
|
+
"""Verify StakingContract init does NOT make RPC calls."""
|
|
30
|
+
mock_interface, mock_contract = mock_chain_interface
|
|
31
|
+
|
|
32
|
+
# Reset ContractCache
|
|
33
|
+
ContractCache().clear()
|
|
34
|
+
|
|
35
|
+
# Instantiate logic
|
|
36
|
+
contract = StakingContract(address="0x123", chain_name="gnosis")
|
|
37
|
+
|
|
38
|
+
# Assert NO calls to call yet (since we mock with_retry to execute immediately, 0 calls means 0 executions)
|
|
39
|
+
assert mock_interface.with_retry.call_count == 0
|
|
40
|
+
|
|
41
|
+
# Setup return value
|
|
42
|
+
# livenessPeriod is a property that calls "livenessPeriod" on contract
|
|
43
|
+
mock_contract.functions.livenessPeriod.return_value.call.return_value = 3600
|
|
44
|
+
|
|
45
|
+
# Access property
|
|
46
|
+
val = contract.liveness_period
|
|
47
|
+
assert val == 3600
|
|
48
|
+
|
|
49
|
+
# Assert 1 call
|
|
50
|
+
assert mock_contract.functions.livenessPeriod.return_value.call.call_count == 1
|
|
51
|
+
|
|
52
|
+
# Access again
|
|
53
|
+
val = contract.liveness_period
|
|
54
|
+
|
|
55
|
+
# Assert still 1 call (cached)
|
|
56
|
+
assert mock_contract.functions.livenessPeriod.return_value.call.call_count == 1
|
|
57
|
+
|
|
58
|
+
def test_contract_cache_singleton(mock_chain_interface):
|
|
59
|
+
"""Verify ContractCache returns same instance and reuses property cache."""
|
|
60
|
+
mock_interface, mock_contract = mock_chain_interface
|
|
61
|
+
ContractCache().clear()
|
|
62
|
+
|
|
63
|
+
c1 = ContractCache().get_contract(StakingContract, "0xABC", "gnosis")
|
|
64
|
+
c2 = ContractCache().get_contract(StakingContract, "0xabc", "gnosis") # Check ignore case
|
|
65
|
+
|
|
66
|
+
assert c1 is c2
|
|
67
|
+
|
|
68
|
+
# populate cache on c1
|
|
69
|
+
mock_contract.functions.maxNumServices.return_value.call.return_value = 500
|
|
70
|
+
|
|
71
|
+
val1 = c1.max_num_services
|
|
72
|
+
assert val1 == 500
|
|
73
|
+
assert mock_contract.functions.maxNumServices.return_value.call.call_count == 1
|
|
74
|
+
|
|
75
|
+
# access on c2
|
|
76
|
+
val2 = c2.max_num_services
|
|
77
|
+
assert val2 == 500
|
|
78
|
+
# Call count should NOT increase
|
|
79
|
+
assert mock_contract.functions.maxNumServices.return_value.call.call_count == 1
|
|
80
|
+
|
|
81
|
+
def test_epoch_aware_caching(mock_chain_interface):
|
|
82
|
+
"""Verify ts_checkpoint caching logic."""
|
|
83
|
+
mock_interface, mock_contract = mock_chain_interface
|
|
84
|
+
ContractCache().clear()
|
|
85
|
+
contract = StakingContract(address="0xEpoch", chain_name="gnosis")
|
|
86
|
+
|
|
87
|
+
# Mock return values for tsCheckpoint
|
|
88
|
+
# We use side_effect on the call() method to simulate changing return values if needed
|
|
89
|
+
# But here we just want it to return 1000 once
|
|
90
|
+
mock_contract.functions.tsCheckpoint.return_value.call.return_value = 1000
|
|
91
|
+
|
|
92
|
+
# Set liveness period in cache to avoid RPC call for it
|
|
93
|
+
contract._contract_params_cache["livenessPeriod"] = 600
|
|
94
|
+
|
|
95
|
+
# 1. Fetch ts_checkpoint
|
|
96
|
+
ts = contract.ts_checkpoint()
|
|
97
|
+
assert ts == 1000
|
|
98
|
+
assert mock_contract.functions.tsCheckpoint.return_value.call.call_count == 1
|
|
99
|
+
|
|
100
|
+
# 2. Call again - should be cached
|
|
101
|
+
ts2 = contract.ts_checkpoint()
|
|
102
|
+
assert ts2 == 1000
|
|
103
|
+
assert mock_contract.functions.tsCheckpoint.return_value.call.call_count == 1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|