genlayer-test 1.0.0__tar.gz → 2.1.0__tar.gz

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.
Files changed (82) hide show
  1. {genlayer_test-1.0.0/genlayer_test.egg-info → genlayer_test-2.1.0}/PKG-INFO +23 -8
  2. genlayer_test-1.0.0/PKG-INFO → genlayer_test-2.1.0/README.md +21 -29
  3. genlayer_test-1.0.0/README.md → genlayer_test-2.1.0/genlayer_test.egg-info/PKG-INFO +44 -6
  4. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/genlayer_test.egg-info/SOURCES.txt +1 -0
  5. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/genlayer_test.egg-info/requires.txt +1 -1
  6. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/contracts/contract.py +18 -6
  7. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/contracts/contract_factory.py +30 -9
  8. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/contracts/contract_functions.py +9 -8
  9. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/types.py +1 -0
  10. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest_cli/config/plugin.py +18 -2
  11. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest_cli/config/types.py +25 -0
  12. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest_cli/config/user.py +12 -2
  13. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/pyproject.toml +2 -2
  14. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/football_prediction_market.py +1 -1
  15. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_intelligent_oracle_factory.py +5 -21
  16. genlayer_test-2.1.0/tests/gltest_cli/config/test_config_integration.py +432 -0
  17. genlayer_test-2.1.0/tests/gltest_cli/config/test_general_config.py +406 -0
  18. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/gltest_cli/config/test_plugin.py +89 -0
  19. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/gltest_cli/config/test_user.py +10 -0
  20. genlayer_test-1.0.0/tests/gltest_cli/config/test_general_config.py +0 -149
  21. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/LICENSE +0 -0
  22. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/genlayer_test.egg-info/dependency_links.txt +0 -0
  23. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/genlayer_test.egg-info/entry_points.txt +0 -0
  24. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/genlayer_test.egg-info/top_level.txt +0 -0
  25. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/__init__.py +0 -0
  26. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/accounts.py +0 -0
  27. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/artifacts/__init__.py +0 -0
  28. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/artifacts/contract.py +0 -0
  29. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/assertions.py +0 -0
  30. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/clients.py +0 -0
  31. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/contracts/__init__.py +0 -0
  32. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/contracts/method_stats.py +0 -0
  33. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/contracts/stats_collector.py +0 -0
  34. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/contracts/utils.py +0 -0
  35. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/exceptions.py +0 -0
  36. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/fixtures.py +0 -0
  37. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/helpers/__init__.py +0 -0
  38. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/helpers/fixture_snapshot.py +0 -0
  39. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/helpers/take_snapshot.py +0 -0
  40. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest/logging.py +0 -0
  41. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest_cli/config/__init__.py +0 -0
  42. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest_cli/config/constants.py +0 -0
  43. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest_cli/config/general.py +0 -0
  44. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest_cli/config/pytest_context.py +0 -0
  45. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest_cli/logging.py +0 -0
  46. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/gltest_cli/main.py +0 -0
  47. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/setup.cfg +0 -0
  48. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/__init__.py +0 -0
  49. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/conftest.py +0 -0
  50. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/intelligent_oracle.py +0 -0
  51. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/intelligent_oracle_factory.py +0 -0
  52. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/llm_erc20.py +0 -0
  53. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/log_indexer.py +0 -0
  54. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/multi_file_contract/__init__.py +0 -0
  55. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/multi_file_contract/other.py +0 -0
  56. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/multi_read_erc20.py +0 -0
  57. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/multi_tenant_storage.py +0 -0
  58. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/read_erc20.py +0 -0
  59. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/storage.py +0 -0
  60. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/user_storage.py +0 -0
  61. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/contracts/wizard_of_coin.py +0 -0
  62. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_football_prediction_market.py +0 -0
  63. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_llm_erc20.py +0 -0
  64. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_llm_erc20_analyze.py +0 -0
  65. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_log_indexer.py +0 -0
  66. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_multi_file_contract.py +0 -0
  67. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_multi_file_contract_legacy.py +0 -0
  68. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_multi_read_erc20.py +0 -0
  69. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_multi_tenant_storage.py +0 -0
  70. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_read_erc20.py +0 -0
  71. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_storage.py +0 -0
  72. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_storage_legacy.py +0 -0
  73. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_user_storage.py +0 -0
  74. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/examples/tests/test_wizard_of_coin.py +0 -0
  75. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/gltest/__init__.py +0 -0
  76. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/gltest/artifact/__init__.py +0 -0
  77. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/gltest/artifact/contracts/duplicate_ic_contract_1.py +0 -0
  78. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/gltest/artifact/contracts/duplicate_ic_contract_2.py +0 -0
  79. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/gltest/artifact/contracts/not_ic_contract.py +0 -0
  80. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/gltest/artifact/test_contract_definition.py +0 -0
  81. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/gltest/assertions/test_assertions.py +0 -0
  82. {genlayer_test-1.0.0 → genlayer_test-2.1.0}/tests/gltest_cli/__init__.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: genlayer-test
3
- Version: 1.0.0
3
+ Version: 2.1.0
4
4
  Summary: GenLayer Testing Suite
5
5
  Author: GenLayer
6
6
  License-Expression: MIT
@@ -15,7 +15,7 @@ Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
16
  Requires-Dist: pytest
17
17
  Requires-Dist: setuptools>=77.0
18
- Requires-Dist: genlayer-py==0.7.1
18
+ Requires-Dist: genlayer-py==0.7.2
19
19
  Requires-Dist: colorama>=0.4.6
20
20
  Requires-Dist: pyyaml
21
21
  Requires-Dist: python-dotenv
@@ -114,6 +114,7 @@ networks:
114
114
 
115
115
  localnet: # Local development network configuration
116
116
  url: "http://127.0.0.1:4000/api"
117
+ leader_only: false # Set to true to run all contracts in leader-only mode by default
117
118
 
118
119
  testnet_asimov: # Test network configuration
119
120
  id: 4221
@@ -125,6 +126,7 @@ networks:
125
126
 
126
127
  paths:
127
128
  contracts: "contracts" # Path to your contracts directory
129
+ artifacts: "artifacts" # Path to your artifacts directory
128
130
 
129
131
  environment: .env # Path to your environment file containing private keys and other secrets
130
132
  ```
@@ -137,12 +139,14 @@ Key configuration sections:
137
139
  - `url`: The RPC endpoint for the network
138
140
  - `id`: Chain ID
139
141
  - `accounts`: List of account private keys (using environment variables)
142
+ - `leader_only`: Leader only mode
140
143
  - Special case for `localnet`:
141
144
  - If a network is named `localnet`, missing fields will be filled with default values
142
145
  - For all other network names, `id`, `url`, and `accounts` are required fields
143
146
 
144
147
  2. **Paths**: Define important directory paths
145
148
  - `contracts`: Location of your contract files
149
+ - `artifacts`: Location of your artifacts files (analysis results will be stored here)
146
150
 
147
151
  3. **Environment**: Path to your `.env` file containing sensitive information like private keys
148
152
 
@@ -231,6 +235,20 @@ def test_with_mocked_llm(setup_validators):
231
235
 
232
236
  Note: This feature is only available when running tests on localnet.
233
237
 
238
+ 11. Run tests with leader-only mode enabled
239
+ ```bash
240
+ $ gltest --leader-only
241
+ ```
242
+ The `--leader-only` flag configures all contract deployments and write operations to run only on the leader node. This is useful for:
243
+ - Faster test execution by avoiding consensus
244
+ - Testing specific leader-only scenarios
245
+ - Development and debugging purposes
246
+ - Reducing computational overhead in test environments
247
+
248
+ When this flag is enabled, all contracts deployed and all write transactions will automatically use leader-only mode, regardless of individual method parameters.
249
+
250
+ **Note:** Leader-only mode is only available for studio-based networks (localhost, 127.0.0.1, *.genlayer.com, *.genlayerlabs.com). When enabled on other networks, it will have no effect and a warning will be logged.
251
+
234
252
  ## 🚀 Key Features
235
253
 
236
254
  - **Pytest Integration** – Extends pytest to support intelligent contract testing, making it familiar and easy to adopt.
@@ -251,8 +269,9 @@ Before diving into the examples, let's understand the basic project structure:
251
269
  genlayer-example/
252
270
  ├── contracts/ # Contract definitions
253
271
  │ └── storage.py # Example storage contract
254
- └── test/ # Test files
255
- └── test_contract.py # Contract test cases
272
+ ├── test/ # Test files
273
+ └── test_contract.py # Contract test cases
274
+ └── gltest.config.yaml # Configuration file
256
275
  ```
257
276
 
258
277
  ### Storage Contract Example
@@ -311,7 +330,6 @@ def test_deployment():
311
330
  args=["initial_value"], # Constructor arguments
312
331
  account=get_default_account(), # Account to deploy from
313
332
  consensus_max_rotations=3, # Optional: max consensus rotations
314
- leader_only=False, # Optional: whether to run only on leader
315
333
  )
316
334
 
317
335
  # Contract is now deployed and ready to use
@@ -357,7 +375,6 @@ def test_write_methods():
357
375
  ).transact(
358
376
  value=0, # Optional: amount of native currency to send
359
377
  consensus_max_rotations=3, # Optional: max consensus rotations
360
- leader_only=False, # Optional: whether to run only on leader
361
378
  wait_interval=1, # Optional: seconds between status checks
362
379
  wait_retries=10, # Optional: max number of retries
363
380
  )
@@ -604,13 +621,11 @@ The `.analyze()` method helps you:
604
621
  # Try with increased consensus parameters
605
622
  contract = factory.deploy(
606
623
  consensus_max_rotations=5, # Increase number of consensus rotations
607
- leader_only=True, # Try leader-only mode for faster execution
608
624
  )
609
625
 
610
626
  # For critical operations, use more conservative settings
611
627
  contract = factory.deploy(
612
628
  consensus_max_rotations=10, # More rotations for better reliability
613
- leader_only=False, # Full consensus for better security
614
629
  wait_interval=3, # Longer wait between checks
615
630
  wait_retries=30 # More retries for consensus
616
631
  )
@@ -1,26 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: genlayer-test
3
- Version: 1.0.0
4
- Summary: GenLayer Testing Suite
5
- Author: GenLayer
6
- License-Expression: MIT
7
- Classifier: Development Status :: 4 - Beta
8
- Classifier: Intended Audience :: Developers
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: Programming Language :: Python :: 3.12
11
- Classifier: Programming Language :: Python :: 3.13
12
- Classifier: Topic :: Software Development :: Testing
13
- Requires-Python: >=3.12
14
- Description-Content-Type: text/markdown
15
- License-File: LICENSE
16
- Requires-Dist: pytest
17
- Requires-Dist: setuptools>=77.0
18
- Requires-Dist: genlayer-py==0.7.1
19
- Requires-Dist: colorama>=0.4.6
20
- Requires-Dist: pyyaml
21
- Requires-Dist: python-dotenv
22
- Dynamic: license-file
23
-
24
1
  # GenLayer Testing Suite
25
2
 
26
3
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/license/mit/)
@@ -114,6 +91,7 @@ networks:
114
91
 
115
92
  localnet: # Local development network configuration
116
93
  url: "http://127.0.0.1:4000/api"
94
+ leader_only: false # Set to true to run all contracts in leader-only mode by default
117
95
 
118
96
  testnet_asimov: # Test network configuration
119
97
  id: 4221
@@ -125,6 +103,7 @@ networks:
125
103
 
126
104
  paths:
127
105
  contracts: "contracts" # Path to your contracts directory
106
+ artifacts: "artifacts" # Path to your artifacts directory
128
107
 
129
108
  environment: .env # Path to your environment file containing private keys and other secrets
130
109
  ```
@@ -137,12 +116,14 @@ Key configuration sections:
137
116
  - `url`: The RPC endpoint for the network
138
117
  - `id`: Chain ID
139
118
  - `accounts`: List of account private keys (using environment variables)
119
+ - `leader_only`: Leader only mode
140
120
  - Special case for `localnet`:
141
121
  - If a network is named `localnet`, missing fields will be filled with default values
142
122
  - For all other network names, `id`, `url`, and `accounts` are required fields
143
123
 
144
124
  2. **Paths**: Define important directory paths
145
125
  - `contracts`: Location of your contract files
126
+ - `artifacts`: Location of your artifacts files (analysis results will be stored here)
146
127
 
147
128
  3. **Environment**: Path to your `.env` file containing sensitive information like private keys
148
129
 
@@ -231,6 +212,20 @@ def test_with_mocked_llm(setup_validators):
231
212
 
232
213
  Note: This feature is only available when running tests on localnet.
233
214
 
215
+ 11. Run tests with leader-only mode enabled
216
+ ```bash
217
+ $ gltest --leader-only
218
+ ```
219
+ The `--leader-only` flag configures all contract deployments and write operations to run only on the leader node. This is useful for:
220
+ - Faster test execution by avoiding consensus
221
+ - Testing specific leader-only scenarios
222
+ - Development and debugging purposes
223
+ - Reducing computational overhead in test environments
224
+
225
+ When this flag is enabled, all contracts deployed and all write transactions will automatically use leader-only mode, regardless of individual method parameters.
226
+
227
+ **Note:** Leader-only mode is only available for studio-based networks (localhost, 127.0.0.1, *.genlayer.com, *.genlayerlabs.com). When enabled on other networks, it will have no effect and a warning will be logged.
228
+
234
229
  ## 🚀 Key Features
235
230
 
236
231
  - **Pytest Integration** – Extends pytest to support intelligent contract testing, making it familiar and easy to adopt.
@@ -251,8 +246,9 @@ Before diving into the examples, let's understand the basic project structure:
251
246
  genlayer-example/
252
247
  ├── contracts/ # Contract definitions
253
248
  │ └── storage.py # Example storage contract
254
- └── test/ # Test files
255
- └── test_contract.py # Contract test cases
249
+ ├── test/ # Test files
250
+ └── test_contract.py # Contract test cases
251
+ └── gltest.config.yaml # Configuration file
256
252
  ```
257
253
 
258
254
  ### Storage Contract Example
@@ -311,7 +307,6 @@ def test_deployment():
311
307
  args=["initial_value"], # Constructor arguments
312
308
  account=get_default_account(), # Account to deploy from
313
309
  consensus_max_rotations=3, # Optional: max consensus rotations
314
- leader_only=False, # Optional: whether to run only on leader
315
310
  )
316
311
 
317
312
  # Contract is now deployed and ready to use
@@ -357,7 +352,6 @@ def test_write_methods():
357
352
  ).transact(
358
353
  value=0, # Optional: amount of native currency to send
359
354
  consensus_max_rotations=3, # Optional: max consensus rotations
360
- leader_only=False, # Optional: whether to run only on leader
361
355
  wait_interval=1, # Optional: seconds between status checks
362
356
  wait_retries=10, # Optional: max number of retries
363
357
  )
@@ -604,13 +598,11 @@ The `.analyze()` method helps you:
604
598
  # Try with increased consensus parameters
605
599
  contract = factory.deploy(
606
600
  consensus_max_rotations=5, # Increase number of consensus rotations
607
- leader_only=True, # Try leader-only mode for faster execution
608
601
  )
609
602
 
610
603
  # For critical operations, use more conservative settings
611
604
  contract = factory.deploy(
612
605
  consensus_max_rotations=10, # More rotations for better reliability
613
- leader_only=False, # Full consensus for better security
614
606
  wait_interval=3, # Longer wait between checks
615
607
  wait_retries=30 # More retries for consensus
616
608
  )
@@ -1,3 +1,26 @@
1
+ Metadata-Version: 2.4
2
+ Name: genlayer-test
3
+ Version: 2.1.0
4
+ Summary: GenLayer Testing Suite
5
+ Author: GenLayer
6
+ License-Expression: MIT
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.12
11
+ Classifier: Programming Language :: Python :: 3.13
12
+ Classifier: Topic :: Software Development :: Testing
13
+ Requires-Python: >=3.12
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Requires-Dist: pytest
17
+ Requires-Dist: setuptools>=77.0
18
+ Requires-Dist: genlayer-py==0.7.2
19
+ Requires-Dist: colorama>=0.4.6
20
+ Requires-Dist: pyyaml
21
+ Requires-Dist: python-dotenv
22
+ Dynamic: license-file
23
+
1
24
  # GenLayer Testing Suite
2
25
 
3
26
  [![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](https://opensource.org/license/mit/)
@@ -91,6 +114,7 @@ networks:
91
114
 
92
115
  localnet: # Local development network configuration
93
116
  url: "http://127.0.0.1:4000/api"
117
+ leader_only: false # Set to true to run all contracts in leader-only mode by default
94
118
 
95
119
  testnet_asimov: # Test network configuration
96
120
  id: 4221
@@ -102,6 +126,7 @@ networks:
102
126
 
103
127
  paths:
104
128
  contracts: "contracts" # Path to your contracts directory
129
+ artifacts: "artifacts" # Path to your artifacts directory
105
130
 
106
131
  environment: .env # Path to your environment file containing private keys and other secrets
107
132
  ```
@@ -114,12 +139,14 @@ Key configuration sections:
114
139
  - `url`: The RPC endpoint for the network
115
140
  - `id`: Chain ID
116
141
  - `accounts`: List of account private keys (using environment variables)
142
+ - `leader_only`: Leader only mode
117
143
  - Special case for `localnet`:
118
144
  - If a network is named `localnet`, missing fields will be filled with default values
119
145
  - For all other network names, `id`, `url`, and `accounts` are required fields
120
146
 
121
147
  2. **Paths**: Define important directory paths
122
148
  - `contracts`: Location of your contract files
149
+ - `artifacts`: Location of your artifacts files (analysis results will be stored here)
123
150
 
124
151
  3. **Environment**: Path to your `.env` file containing sensitive information like private keys
125
152
 
@@ -208,6 +235,20 @@ def test_with_mocked_llm(setup_validators):
208
235
 
209
236
  Note: This feature is only available when running tests on localnet.
210
237
 
238
+ 11. Run tests with leader-only mode enabled
239
+ ```bash
240
+ $ gltest --leader-only
241
+ ```
242
+ The `--leader-only` flag configures all contract deployments and write operations to run only on the leader node. This is useful for:
243
+ - Faster test execution by avoiding consensus
244
+ - Testing specific leader-only scenarios
245
+ - Development and debugging purposes
246
+ - Reducing computational overhead in test environments
247
+
248
+ When this flag is enabled, all contracts deployed and all write transactions will automatically use leader-only mode, regardless of individual method parameters.
249
+
250
+ **Note:** Leader-only mode is only available for studio-based networks (localhost, 127.0.0.1, *.genlayer.com, *.genlayerlabs.com). When enabled on other networks, it will have no effect and a warning will be logged.
251
+
211
252
  ## 🚀 Key Features
212
253
 
213
254
  - **Pytest Integration** – Extends pytest to support intelligent contract testing, making it familiar and easy to adopt.
@@ -228,8 +269,9 @@ Before diving into the examples, let's understand the basic project structure:
228
269
  genlayer-example/
229
270
  ├── contracts/ # Contract definitions
230
271
  │ └── storage.py # Example storage contract
231
- └── test/ # Test files
232
- └── test_contract.py # Contract test cases
272
+ ├── test/ # Test files
273
+ └── test_contract.py # Contract test cases
274
+ └── gltest.config.yaml # Configuration file
233
275
  ```
234
276
 
235
277
  ### Storage Contract Example
@@ -288,7 +330,6 @@ def test_deployment():
288
330
  args=["initial_value"], # Constructor arguments
289
331
  account=get_default_account(), # Account to deploy from
290
332
  consensus_max_rotations=3, # Optional: max consensus rotations
291
- leader_only=False, # Optional: whether to run only on leader
292
333
  )
293
334
 
294
335
  # Contract is now deployed and ready to use
@@ -334,7 +375,6 @@ def test_write_methods():
334
375
  ).transact(
335
376
  value=0, # Optional: amount of native currency to send
336
377
  consensus_max_rotations=3, # Optional: max consensus rotations
337
- leader_only=False, # Optional: whether to run only on leader
338
378
  wait_interval=1, # Optional: seconds between status checks
339
379
  wait_retries=10, # Optional: max number of retries
340
380
  )
@@ -581,13 +621,11 @@ The `.analyze()` method helps you:
581
621
  # Try with increased consensus parameters
582
622
  contract = factory.deploy(
583
623
  consensus_max_rotations=5, # Increase number of consensus rotations
584
- leader_only=True, # Try leader-only mode for faster execution
585
624
  )
586
625
 
587
626
  # For critical operations, use more conservative settings
588
627
  contract = factory.deploy(
589
628
  consensus_max_rotations=10, # More rotations for better reliability
590
- leader_only=False, # Full consensus for better security
591
629
  wait_interval=3, # Longer wait between checks
592
630
  wait_retries=30 # More retries for consensus
593
631
  )
@@ -73,6 +73,7 @@ tests/gltest/artifact/contracts/duplicate_ic_contract_2.py
73
73
  tests/gltest/artifact/contracts/not_ic_contract.py
74
74
  tests/gltest/assertions/test_assertions.py
75
75
  tests/gltest_cli/__init__.py
76
+ tests/gltest_cli/config/test_config_integration.py
76
77
  tests/gltest_cli/config/test_general_config.py
77
78
  tests/gltest_cli/config/test_plugin.py
78
79
  tests/gltest_cli/config/test_user.py
@@ -1,6 +1,6 @@
1
1
  pytest
2
2
  setuptools>=77.0
3
- genlayer-py==0.7.1
3
+ genlayer-py==0.7.2
4
4
  colorama>=0.4.6
5
5
  pyyaml
6
6
  python-dotenv
@@ -2,7 +2,12 @@ import types
2
2
  from eth_account.signers.local import LocalAccount
3
3
  from dataclasses import dataclass
4
4
  from gltest.clients import get_gl_client
5
- from gltest.types import CalldataEncodable, GenLayerTransaction, TransactionStatus
5
+ from gltest.types import (
6
+ CalldataEncodable,
7
+ GenLayerTransaction,
8
+ TransactionStatus,
9
+ TransactionHashVariant,
10
+ )
6
11
  from typing import List, Any, Optional, Dict, Callable
7
12
  from gltest_cli.config.general import get_general_config
8
13
  from .contract_functions import ContractFunction
@@ -18,13 +23,16 @@ def read_contract_wrapper(
18
23
  Wrapper to the contract read method.
19
24
  """
20
25
 
21
- def call_method():
26
+ def call_method(
27
+ transaction_hash_variant: TransactionHashVariant = TransactionHashVariant.LATEST_NONFINAL,
28
+ ):
22
29
  client = get_gl_client()
23
30
  return client.read_contract(
24
31
  address=self.address,
25
32
  function_name=method_name,
26
33
  account=self.account,
27
34
  args=args,
35
+ transaction_hash_variant=transaction_hash_variant,
28
36
  )
29
37
 
30
38
  return ContractFunction(
@@ -46,12 +54,11 @@ def write_contract_wrapper(
46
54
  def transact_method(
47
55
  value: int = 0,
48
56
  consensus_max_rotations: Optional[int] = None,
49
- leader_only: bool = False,
50
- wait_transaction_status: TransactionStatus = TransactionStatus.FINALIZED,
57
+ wait_transaction_status: TransactionStatus = TransactionStatus.ACCEPTED,
51
58
  wait_interval: Optional[int] = None,
52
59
  wait_retries: Optional[int] = None,
53
- wait_triggered_transactions: bool = True,
54
- wait_triggered_transactions_status: TransactionStatus = TransactionStatus.FINALIZED,
60
+ wait_triggered_transactions: bool = False,
61
+ wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
55
62
  ):
56
63
  """
57
64
  Transact the contract method.
@@ -67,6 +74,11 @@ def write_contract_wrapper(
67
74
  if wait_retries is not None
68
75
  else general_config.get_default_wait_retries()
69
76
  )
77
+ leader_only = (
78
+ general_config.get_leader_only()
79
+ if general_config.check_studio_based_rpc()
80
+ else False
81
+ )
70
82
  client = get_gl_client()
71
83
  tx_hash = client.write_contract(
72
84
  address=self.address,
@@ -23,7 +23,6 @@ from gltest.exceptions import DeploymentError
23
23
  from gltest_cli.config.general import get_general_config
24
24
 
25
25
 
26
-
27
26
  @dataclass
28
27
  class ContractFactory:
29
28
  """
@@ -108,19 +107,31 @@ class ContractFactory:
108
107
  args: List[Any] = [],
109
108
  account: Optional[LocalAccount] = None,
110
109
  consensus_max_rotations: Optional[int] = None,
111
- leader_only: bool = False,
112
110
  wait_interval: Optional[int] = None,
113
111
  wait_retries: Optional[int] = None,
114
- wait_transaction_status: TransactionStatus = TransactionStatus.FINALIZED,
112
+ wait_transaction_status: TransactionStatus = TransactionStatus.ACCEPTED,
113
+ wait_triggered_transactions: bool = False,
114
+ wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
115
115
  ) -> Contract:
116
116
  """
117
117
  Deploy the contract
118
118
  """
119
119
  general_config = get_general_config()
120
- if wait_interval is None:
121
- wait_interval = general_config.get_default_wait_interval()
122
- if wait_retries is None:
123
- wait_retries = general_config.get_default_wait_retries()
120
+ actual_wait_interval = (
121
+ wait_interval
122
+ if wait_interval is not None
123
+ else general_config.get_default_wait_interval()
124
+ )
125
+ actual_wait_retries = (
126
+ wait_retries
127
+ if wait_retries is not None
128
+ else general_config.get_default_wait_retries()
129
+ )
130
+ leader_only = (
131
+ general_config.get_leader_only()
132
+ if general_config.check_studio_based_rpc()
133
+ else False
134
+ )
124
135
 
125
136
  client = get_gl_client()
126
137
  try:
@@ -134,14 +145,24 @@ class ContractFactory:
134
145
  tx_receipt = client.wait_for_transaction_receipt(
135
146
  transaction_hash=tx_hash,
136
147
  status=wait_transaction_status,
137
- interval=wait_interval,
138
- retries=wait_retries,
148
+ interval=actual_wait_interval,
149
+ retries=actual_wait_retries,
139
150
  )
140
151
  if tx_execution_failed(tx_receipt):
141
152
  raise ValueError(
142
153
  f"Deployment transaction finalized with error: {tx_receipt}"
143
154
  )
144
155
 
156
+ if wait_triggered_transactions:
157
+ triggered_transactions = tx_receipt["triggered_transactions"]
158
+ for triggered_transaction in triggered_transactions:
159
+ client.wait_for_transaction_receipt(
160
+ transaction_hash=triggered_transaction,
161
+ status=wait_triggered_transactions_status,
162
+ interval=actual_wait_interval,
163
+ retries=actual_wait_retries,
164
+ )
165
+
145
166
  if (
146
167
  "tx_data_decoded" in tx_receipt
147
168
  and "contract_address" in tx_receipt["tx_data_decoded"]
@@ -1,6 +1,6 @@
1
1
  from dataclasses import dataclass
2
2
  from typing import Callable, Optional, Dict, Any
3
- from gltest.types import TransactionStatus
3
+ from gltest.types import TransactionStatus, TransactionHashVariant
4
4
 
5
5
 
6
6
  @dataclass
@@ -11,28 +11,29 @@ class ContractFunction:
11
11
  analyze_method: Optional[Callable] = None
12
12
  transact_method: Optional[Callable] = None
13
13
 
14
- def call(self):
14
+ def call(
15
+ self,
16
+ transaction_hash_variant: TransactionHashVariant = TransactionHashVariant.LATEST_NONFINAL,
17
+ ):
15
18
  if not self.read_only:
16
19
  raise ValueError("call() not implemented for non-readonly method")
17
- return self.call_method()
20
+ return self.call_method(transaction_hash_variant=transaction_hash_variant)
18
21
 
19
22
  def transact(
20
23
  self,
21
24
  value: int = 0,
22
25
  consensus_max_rotations: Optional[int] = None,
23
- leader_only: bool = False,
24
- wait_transaction_status: TransactionStatus = TransactionStatus.FINALIZED,
26
+ wait_transaction_status: TransactionStatus = TransactionStatus.ACCEPTED,
25
27
  wait_interval: Optional[int] = None,
26
28
  wait_retries: Optional[int] = None,
27
- wait_triggered_transactions: bool = True,
28
- wait_triggered_transactions_status: TransactionStatus = TransactionStatus.FINALIZED,
29
+ wait_triggered_transactions: bool = False,
30
+ wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
29
31
  ):
30
32
  if self.read_only:
31
33
  raise ValueError("Cannot transact read-only method")
32
34
  return self.transact_method(
33
35
  value=value,
34
36
  consensus_max_rotations=consensus_max_rotations,
35
- leader_only=leader_only,
36
37
  wait_transaction_status=wait_transaction_status,
37
38
  wait_interval=wait_interval,
38
39
  wait_retries=wait_retries,
@@ -4,4 +4,5 @@ from genlayer_py.types import (
4
4
  GenLayerTransaction,
5
5
  TransactionStatus,
6
6
  CalldataEncodable,
7
+ TransactionHashVariant,
7
8
  )
@@ -32,14 +32,14 @@ def pytest_addoption(parser):
32
32
  group.addoption(
33
33
  "--default-wait-interval",
34
34
  action="store",
35
- default=10000,
35
+ default=3000,
36
36
  help="Default interval (ms) between transaction receipt checks",
37
37
  )
38
38
 
39
39
  group.addoption(
40
40
  "--default-wait-retries",
41
41
  action="store",
42
- default=15,
42
+ default=50,
43
43
  help="Default number of retries for transaction receipt checks",
44
44
  )
45
45
 
@@ -64,6 +64,13 @@ def pytest_addoption(parser):
64
64
  help="Test with mocks",
65
65
  )
66
66
 
67
+ group.addoption(
68
+ "--leader-only",
69
+ action="store_true",
70
+ default=False,
71
+ help="Run contracts in leader-only mode",
72
+ )
73
+
67
74
 
68
75
  def pytest_configure(config):
69
76
  general_config = get_general_config()
@@ -91,6 +98,7 @@ def pytest_configure(config):
91
98
  rpc_url = config.getoption("--rpc-url")
92
99
  network = config.getoption("--network")
93
100
  test_with_mocks = config.getoption("--test-with-mocks")
101
+ leader_only = config.getoption("--leader-only")
94
102
 
95
103
  plugin_config = PluginConfig()
96
104
  plugin_config.contracts_dir = (
@@ -104,6 +112,7 @@ def pytest_configure(config):
104
112
  plugin_config.rpc_url = rpc_url
105
113
  plugin_config.network_name = network
106
114
  plugin_config.test_with_mocks = test_with_mocks
115
+ plugin_config.leader_only = leader_only
107
116
 
108
117
  general_config.plugin_config = plugin_config
109
118
 
@@ -137,6 +146,13 @@ def pytest_sessionstart(session):
137
146
  logger.info(f" Default wait retries: {general_config.get_default_wait_retries()}")
138
147
  logger.info(f" Test with mocks: {general_config.get_test_with_mocks()}")
139
148
 
149
+ if general_config.get_leader_only() and not general_config.check_studio_based_rpc():
150
+ logger.warning(
151
+ "Leader only mode: True (enabled on non-studio network - will have no effect)"
152
+ )
153
+ else:
154
+ logger.info(f" Leader only mode: {general_config.get_leader_only()}")
155
+
140
156
 
141
157
  def pytest_runtest_setup(item):
142
158
  _pytest_context.current_item = item
@@ -21,6 +21,7 @@ class PluginConfig:
21
21
  default_wait_retries: Optional[int] = None
22
22
  network_name: Optional[str] = None
23
23
  test_with_mocks: bool = False
24
+ leader_only: bool = False
24
25
 
25
26
 
26
27
  @dataclass
@@ -29,6 +30,7 @@ class NetworkConfigData:
29
30
  url: Optional[str] = None
30
31
  accounts: Optional[List[str]] = None
31
32
  from_account: Optional[str] = None
33
+ leader_only: bool = False
32
34
 
33
35
  def __post_init__(self):
34
36
  if self.id is not None and not isinstance(self.id, int):
@@ -157,8 +159,31 @@ class GeneralConfig:
157
159
  def get_test_with_mocks(self) -> bool:
158
160
  return self.plugin_config.test_with_mocks
159
161
 
162
+ def get_leader_only(self) -> bool:
163
+ if self.plugin_config.leader_only:
164
+ return True
165
+ network_name = self.get_network_name()
166
+ if network_name in self.user_config.networks:
167
+ network_config = self.user_config.networks[network_name]
168
+ return network_config.leader_only
169
+ return False
170
+
160
171
  def check_local_rpc(self) -> bool:
161
172
  SUPPORTED_RPC_DOMAINS = ["localhost", "127.0.0.1"]
162
173
  rpc_url = self.get_rpc_url()
163
174
  domain = urlparse(rpc_url).netloc.split(":")[0] # Extract domain without port
164
175
  return domain in SUPPORTED_RPC_DOMAINS
176
+
177
+ def check_studio_based_rpc(self) -> bool:
178
+ SUPPORTED_RPC_DOMAINS = ["localhost", "127.0.0.1"]
179
+ rpc_url = self.get_rpc_url()
180
+ domain = urlparse(rpc_url).netloc.split(":")[0] # Extract domain without port
181
+
182
+ if domain in SUPPORTED_RPC_DOMAINS:
183
+ return True
184
+
185
+ # Check .genlayer.com or .genlayerlabs.com subdomains
186
+ if domain.endswith(".genlayer.com") or domain.endswith(".genlayerlabs.com"):
187
+ return True
188
+
189
+ return False