genlayer-test 0.6.0__py3-none-any.whl → 0.8.0__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.
- {genlayer_test-0.6.0.dist-info → genlayer_test-0.8.0.dist-info}/METADATA +217 -3
- {genlayer_test-0.6.0.dist-info → genlayer_test-0.8.0.dist-info}/RECORD +18 -13
- gltest/__init__.py +3 -0
- gltest/contracts/contract.py +24 -0
- gltest/contracts/contract_factory.py +14 -0
- gltest/contracts/contract_functions.py +10 -2
- gltest/contracts/stats_collector.py +11 -4
- gltest/types.py +29 -0
- gltest/validators/__init__.py +3 -0
- gltest/validators/validator_factory.py +136 -0
- tests/examples/contracts/simple_time_contract.py +85 -0
- tests/examples/tests/test_custom_validators.py +65 -0
- tests/examples/tests/test_llm_erc20_analyze.py +5 -1
- tests/examples/tests/test_simple_time_contract.py +90 -0
- {genlayer_test-0.6.0.dist-info → genlayer_test-0.8.0.dist-info}/WHEEL +0 -0
- {genlayer_test-0.6.0.dist-info → genlayer_test-0.8.0.dist-info}/entry_points.txt +0 -0
- {genlayer_test-0.6.0.dist-info → genlayer_test-0.8.0.dist-info}/licenses/LICENSE +0 -0
- {genlayer_test-0.6.0.dist-info → genlayer_test-0.8.0.dist-info}/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: genlayer-test
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.8.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.
|
18
|
+
Requires-Dist: genlayer-py==0.9.0
|
19
19
|
Requires-Dist: colorama>=0.4.6
|
20
20
|
Requires-Dist: pyyaml
|
21
21
|
Requires-Dist: python-dotenv
|
@@ -308,6 +308,7 @@ When this flag is enabled, all contracts deployed and all write transactions wil
|
|
308
308
|
- **State Injection & Consensus Simulation** – Modify contract states dynamically and simulate consensus scenarios for advanced testing.
|
309
309
|
- **Prompt Testing & Statistical Analysis** – Evaluate and statistically test prompts for AI-driven contract execution.
|
310
310
|
- **Scalability to Security & Audit Tools** – Designed to extend into security testing and smart contract auditing.
|
311
|
+
- **Custom Transaction Context** – Set custom validators with specific LLM providers and models, and configure GenVM datetime for deterministic testing scenarios.
|
311
312
|
|
312
313
|
## 📚 Examples
|
313
314
|
|
@@ -387,6 +388,7 @@ def test_deployment():
|
|
387
388
|
args=["initial_value"], # Constructor arguments
|
388
389
|
account=get_default_account(), # Account to deploy from
|
389
390
|
consensus_max_rotations=3, # Optional: max consensus rotations
|
391
|
+
transaction_context=None, # Optional: custom transaction context
|
390
392
|
)
|
391
393
|
|
392
394
|
# Contract is now deployed and ready to use
|
@@ -419,7 +421,9 @@ def test_read_methods():
|
|
419
421
|
contract = factory.deploy()
|
420
422
|
|
421
423
|
# Call a read-only method
|
422
|
-
result = contract.get_storage(args=[]).call(
|
424
|
+
result = contract.get_storage(args=[]).call(
|
425
|
+
transaction_context=None, # Optional: custom transaction context
|
426
|
+
)
|
423
427
|
|
424
428
|
# Assert the result matches the initial value
|
425
429
|
assert result == "initial_value"
|
@@ -446,6 +450,7 @@ def test_write_methods():
|
|
446
450
|
consensus_max_rotations=3, # Optional: max consensus rotations
|
447
451
|
wait_interval=1, # Optional: seconds between status checks
|
448
452
|
wait_retries=10, # Optional: max number of retries
|
453
|
+
transaction_context=None, # Optional: custom transaction context
|
449
454
|
)
|
450
455
|
|
451
456
|
# Verify the transaction was successful
|
@@ -609,6 +614,7 @@ def test_analyze_method():
|
|
609
614
|
config=None, # Optional: provider-specific config
|
610
615
|
plugin=None, # Optional: plugin name
|
611
616
|
plugin_config=None, # Optional: plugin configuration
|
617
|
+
genvm_datetime="2024-01-15T10:30:00Z", # Optional: GenVM datetime in ISO format
|
612
618
|
)
|
613
619
|
|
614
620
|
# Access analysis results
|
@@ -757,6 +763,214 @@ def test_with_mocked_llm(setup_validators):
|
|
757
763
|
- The `setup_validators` fixture handles the mock setup when provided with a mock_response
|
758
764
|
- Mocking is particularly useful for CI/CD pipelines where deterministic results are required
|
759
765
|
|
766
|
+
### Custom Transaction Context
|
767
|
+
|
768
|
+
The GenLayer Testing Suite allows you to customize the transaction execution environment by providing a `transaction_context` parameter with custom validators and GenVM datetime settings.
|
769
|
+
|
770
|
+
#### Using Transaction Context
|
771
|
+
|
772
|
+
Set custom validators and GenVM datetime for deterministic testing:
|
773
|
+
|
774
|
+
```python
|
775
|
+
from gltest import get_contract_factory, get_validator_factory
|
776
|
+
|
777
|
+
def test_with_custom_transaction_context():
|
778
|
+
factory = get_contract_factory("MyContract")
|
779
|
+
validator_factory = get_validator_factory()
|
780
|
+
|
781
|
+
# Create custom validators
|
782
|
+
validators = validator_factory.batch_create_validators(
|
783
|
+
count=3,
|
784
|
+
stake=10,
|
785
|
+
provider="openai",
|
786
|
+
model="gpt-4o",
|
787
|
+
config={"temperature": 0.7, "max_tokens": 1000},
|
788
|
+
plugin="openai-compatible",
|
789
|
+
plugin_config={"api_key_env_var": "OPENAI_API_KEY"}
|
790
|
+
)
|
791
|
+
|
792
|
+
# Create transaction context with custom validators and datetime
|
793
|
+
transaction_context = {
|
794
|
+
"validators": [v.to_dict() for v in validators],
|
795
|
+
"genvm_datetime": "2024-03-15T14:30:00Z" # ISO format datetime
|
796
|
+
}
|
797
|
+
|
798
|
+
# Deploy with custom context
|
799
|
+
contract = factory.deploy(
|
800
|
+
args=["initial_value"],
|
801
|
+
transaction_context=transaction_context
|
802
|
+
)
|
803
|
+
|
804
|
+
# Call methods with custom context
|
805
|
+
result = contract.read_method().call(
|
806
|
+
transaction_context=transaction_context
|
807
|
+
)
|
808
|
+
|
809
|
+
# Write operations with custom context
|
810
|
+
tx_receipt = contract.write_method(args=["value"]).transact(
|
811
|
+
transaction_context=transaction_context
|
812
|
+
)
|
813
|
+
```
|
814
|
+
|
815
|
+
#### Mock Validators with Transaction Context
|
816
|
+
|
817
|
+
Combine mock validators with custom datetime for fully deterministic tests:
|
818
|
+
|
819
|
+
```python
|
820
|
+
def test_with_mocked_context():
|
821
|
+
factory = get_contract_factory("LLMContract")
|
822
|
+
validator_factory = get_validator_factory()
|
823
|
+
|
824
|
+
# Define mock LLM responses
|
825
|
+
mock_response = {
|
826
|
+
"nondet_exec_prompt": {
|
827
|
+
"analyze this": "positive sentiment"
|
828
|
+
},
|
829
|
+
"eq_principle_prompt_comparative": {
|
830
|
+
"values match": True
|
831
|
+
}
|
832
|
+
}
|
833
|
+
|
834
|
+
# Create mock validators
|
835
|
+
mock_validators = validator_factory.batch_create_mock_validators(
|
836
|
+
count=5,
|
837
|
+
mock_llm_response=mock_response
|
838
|
+
)
|
839
|
+
|
840
|
+
# Set up deterministic context
|
841
|
+
transaction_context = {
|
842
|
+
"validators": [v.to_dict() for v in mock_validators],
|
843
|
+
"genvm_datetime": "2024-01-01T00:00:00Z" # Fixed datetime for reproducibility
|
844
|
+
}
|
845
|
+
|
846
|
+
# Deploy and test with deterministic context
|
847
|
+
contract = factory.deploy(transaction_context=transaction_context)
|
848
|
+
|
849
|
+
# All operations will use the same mocked validators and datetime
|
850
|
+
result = contract.analyze_text(args=["analyze this"]).transact(
|
851
|
+
transaction_context=transaction_context
|
852
|
+
)
|
853
|
+
# Result will consistently return "positive sentiment"
|
854
|
+
```
|
855
|
+
|
856
|
+
### Custom Validators
|
857
|
+
|
858
|
+
The GenLayer Testing Suite includes a `get_validator_factory()` function that allows you to create custom validators with specific configurations for testing different LLM providers and consensus scenarios.
|
859
|
+
|
860
|
+
#### Creating Custom Validators
|
861
|
+
|
862
|
+
```python
|
863
|
+
from gltest import get_validator_factory
|
864
|
+
|
865
|
+
def test_with_custom_validators():
|
866
|
+
factory = get_validator_factory()
|
867
|
+
|
868
|
+
# Create validators with different LLM providers
|
869
|
+
openai_validator = factory.create_validator(
|
870
|
+
stake=10,
|
871
|
+
provider="openai",
|
872
|
+
model="gpt-4o",
|
873
|
+
config={"temperature": 0.8, "max_tokens": 2000},
|
874
|
+
plugin="openai-compatible",
|
875
|
+
plugin_config={"api_key_env_var": "OPENAI_API_KEY"}
|
876
|
+
)
|
877
|
+
|
878
|
+
ollama_validator = factory.create_validator(
|
879
|
+
stake=8,
|
880
|
+
provider="ollama",
|
881
|
+
model="mistral",
|
882
|
+
config={"temperature": 0.5},
|
883
|
+
plugin="ollama",
|
884
|
+
plugin_config={"api_url": "http://localhost:11434"}
|
885
|
+
)
|
886
|
+
|
887
|
+
# Use validators in your tests
|
888
|
+
validators = [openai_validator, ollama_validator]
|
889
|
+
# Configure your test environment with these validators
|
890
|
+
```
|
891
|
+
|
892
|
+
#### Batch Creation
|
893
|
+
|
894
|
+
Create multiple validators with the same configuration:
|
895
|
+
|
896
|
+
```python
|
897
|
+
def test_batch_validators():
|
898
|
+
factory = get_validator_factory()
|
899
|
+
|
900
|
+
# Create 5 validators with identical configuration
|
901
|
+
validators = factory.batch_create_validators(
|
902
|
+
count=5,
|
903
|
+
stake=8,
|
904
|
+
provider="openai",
|
905
|
+
model="gpt-4o",
|
906
|
+
config={"temperature": 0.7, "max_tokens": 1000},
|
907
|
+
plugin="openai-compatible",
|
908
|
+
plugin_config={"api_key_env_var": "OPENAI_API_KEY"}
|
909
|
+
)
|
910
|
+
```
|
911
|
+
|
912
|
+
#### Mock Validators
|
913
|
+
|
914
|
+
For deterministic testing, create mock validators that return predefined responses:
|
915
|
+
|
916
|
+
```python
|
917
|
+
def test_with_mock_validators():
|
918
|
+
factory = get_validator_factory()
|
919
|
+
|
920
|
+
# Define mock responses
|
921
|
+
mock_response = {
|
922
|
+
"nondet_exec_prompt": {
|
923
|
+
"What is 2+2?": "4",
|
924
|
+
"Explain quantum physics": "It's complicated"
|
925
|
+
},
|
926
|
+
"eq_principle_prompt_comparative": {
|
927
|
+
"values must match": True
|
928
|
+
},
|
929
|
+
"eq_principle_prompt_non_comparative": {
|
930
|
+
"Is this valid?": True
|
931
|
+
}
|
932
|
+
}
|
933
|
+
|
934
|
+
# Create a single mock validator
|
935
|
+
mock_validator = factory.create_mock_validator(mock_response)
|
936
|
+
|
937
|
+
# Create multiple mock validators
|
938
|
+
mock_validators = factory.batch_create_mock_validators(
|
939
|
+
count=5,
|
940
|
+
mock_llm_response=mock_response
|
941
|
+
)
|
942
|
+
```
|
943
|
+
|
944
|
+
#### Validator Methods
|
945
|
+
|
946
|
+
Each validator object provides useful methods:
|
947
|
+
- `to_dict()`: Convert validator to dictionary format for API calls
|
948
|
+
- `clone()`: Create an identical copy of the validator
|
949
|
+
- `batch_clone(count)`: Create multiple identical copies
|
950
|
+
|
951
|
+
Example:
|
952
|
+
```python
|
953
|
+
def test_validator_cloning():
|
954
|
+
factory = get_validator_factory()
|
955
|
+
|
956
|
+
# Create a base validator
|
957
|
+
base_validator = factory.create_validator(
|
958
|
+
stake=10,
|
959
|
+
provider="openai",
|
960
|
+
model="gpt-4o",
|
961
|
+
config={"temperature": 0.7},
|
962
|
+
plugin="openai-compatible",
|
963
|
+
plugin_config={"api_key_env_var": "OPENAI_API_KEY"}
|
964
|
+
)
|
965
|
+
|
966
|
+
# Clone it to create identical validators
|
967
|
+
cloned = base_validator.clone()
|
968
|
+
multiple_clones = base_validator.batch_clone(3)
|
969
|
+
|
970
|
+
# Convert to dictionary for API usage
|
971
|
+
validator_dict = base_validator.to_dict()
|
972
|
+
```
|
973
|
+
|
760
974
|
## 📝 Best Practices
|
761
975
|
|
762
976
|
1. **Test Organization**
|
@@ -1,25 +1,27 @@
|
|
1
|
-
genlayer_test-0.
|
2
|
-
gltest/__init__.py,sha256=
|
1
|
+
genlayer_test-0.8.0.dist-info/licenses/LICENSE,sha256=che_H4vE0QUx3HvWrAa1_jDEVInift0U6VO15-QqEls,1064
|
2
|
+
gltest/__init__.py,sha256=49112x2CLdYwvCbBZ1laJmMk0NQ7S3u5YUbxPefqhrk,454
|
3
3
|
gltest/accounts.py,sha256=HUmWguJMolggQaZNRPw-LGlRlQCjLLdUanKRowMv6pI,812
|
4
4
|
gltest/assertions.py,sha256=0dEk0VxcHK4I7GZPHxJmz-2jaA60V499gOSR74rZbfM,1748
|
5
5
|
gltest/clients.py,sha256=1dX6wmG3QCevQRLbSaFlHymZSb-sJ5aYwet1IoX2nbA,1554
|
6
6
|
gltest/exceptions.py,sha256=deJPmrTe5gF33qkkKF2IVJY7lc_knI7Ql3N7jZ8aLZs,510
|
7
7
|
gltest/fixtures.py,sha256=EJXmqcC3LD03v07mepacFl58lAdhbLj6bP5rtALYISk,2507
|
8
8
|
gltest/logging.py,sha256=jAkHsuMm-AEx1Xu1srU6W-0YzTwXJB48mCK-OVzAiN4,342
|
9
|
-
gltest/types.py,sha256=
|
9
|
+
gltest/types.py,sha256=H32fHrU5aFMaPHXgEWcHAmLWOZ9pBFVp8PK_ncpVOgM,940
|
10
10
|
gltest/utils.py,sha256=-gHhjrS7i_GhDG3sKOq2qsTtYBt4HHgXHEXh-3RB_rI,573
|
11
11
|
gltest/artifacts/__init__.py,sha256=qTt3TE19gVNWnQLUlt5aDe4nNvJ2YJ1jzDkMmYIsCG0,194
|
12
12
|
gltest/artifacts/contract.py,sha256=KChpmfjZod_0dVB8y-dvWz6IVm7QlIJsgG2ArtvVDaU,6457
|
13
13
|
gltest/contracts/__init__.py,sha256=A9bvEtYOoqoHS8TLlFBfmNOnfwdsJPEf-AZuikagCHM,166
|
14
|
-
gltest/contracts/contract.py,sha256=
|
15
|
-
gltest/contracts/contract_factory.py,sha256=
|
16
|
-
gltest/contracts/contract_functions.py,sha256=
|
14
|
+
gltest/contracts/contract.py,sha256=jLF_ojSM6IIbdGO2_DhsO79r2wZ2Z8eBAJRrZk2qVTI,7748
|
15
|
+
gltest/contracts/contract_factory.py,sha256=PpWh4mKf1hDMv_yms5lwFV_EoXxXiuNfdXbwD74hbAU,8929
|
16
|
+
gltest/contracts/contract_functions.py,sha256=W6Dpw1z-n9EeJxlNtIbeVnzpv4BPABhtgmgjnS8-P0w,2573
|
17
17
|
gltest/contracts/method_stats.py,sha256=zWWjvf7K5VC4yrHpDIR717VF7LYp1RaZ1Hr_RZvWxJA,5150
|
18
|
-
gltest/contracts/stats_collector.py,sha256=
|
18
|
+
gltest/contracts/stats_collector.py,sha256=iwsnoYo5aZbI4SVMH7dR-5CQgkglExXfsvaUDpwcdss,9286
|
19
19
|
gltest/contracts/utils.py,sha256=TTXgcXn9BuRIlKJrjwmU7R3l1IgXsXk2luM-r3lfbbg,296
|
20
20
|
gltest/helpers/__init__.py,sha256=I7HiTu_H7_hP65zY6Wl02r-5eAMr2eZvqBVmusuQLX4,180
|
21
21
|
gltest/helpers/fixture_snapshot.py,sha256=bMgvlEVQBGIQzj7NOyosXWlphI1H2C1o75Zo0C-kGfQ,1931
|
22
22
|
gltest/helpers/take_snapshot.py,sha256=-QkaBvFG4ZsNKv_nCSEsy5Ze1pICOHxVhReSeQmZUlY,1276
|
23
|
+
gltest/validators/__init__.py,sha256=AXboXORF5a8MVtG7jWMT1fJcwGXNzcX6txXQstwX2EU,152
|
24
|
+
gltest/validators/validator_factory.py,sha256=fpb-YyAKuWo4-pXBjrZ_TApYLsm6HHa6kGpbFByRucs,3886
|
23
25
|
gltest_cli/logging.py,sha256=WXVhfq9vT6FtV_jxDqGEGia1ZWSIUKAfmWRnZd_gWQk,1266
|
24
26
|
gltest_cli/main.py,sha256=Ti2-0Ev1x5_cM0D1UKqdgaDt80CDHEQGtdRne2qLm4M,53
|
25
27
|
gltest_cli/config/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -40,21 +42,24 @@ tests/examples/contracts/log_indexer.py,sha256=Nlf8XUt13ujam3k6hbbVrPHK-KJ366Csz
|
|
40
42
|
tests/examples/contracts/multi_read_erc20.py,sha256=28qYqn191Ro3rP7YJtZwL6Sc7JDXTeh8_QoqvdVPdqM,864
|
41
43
|
tests/examples/contracts/multi_tenant_storage.py,sha256=ceq3X4E7pkvSdy7eQMhAoHme4KFedjAcpkfUYBmcgVM,1941
|
42
44
|
tests/examples/contracts/read_erc20.py,sha256=RgH269F0x482WuLLYcacBnZsGJjhgJp6sG_33cV6Z-w,454
|
45
|
+
tests/examples/contracts/simple_time_contract.py,sha256=-9p_umlzUW5X2NL6IknO6Khs_114izSWifP5D2bWCMo,2512
|
43
46
|
tests/examples/contracts/storage.py,sha256=3DD3qvzb0JkVcBtu240e5kaZWgkh-bu6YExqBUYvfaw,501
|
44
47
|
tests/examples/contracts/user_storage.py,sha256=2W2Iv-hQZMkAaPl2RY_F-OeJpD4IlPxgWzN6e1bTkKE,649
|
45
48
|
tests/examples/contracts/wizard_of_coin.py,sha256=Y8daPpoSKdM8wfbCPOIgEdpkLIA1ZMmeg6Hu5fBB-kU,1624
|
46
49
|
tests/examples/contracts/multi_file_contract/__init__.py,sha256=xDn_wS62GhCmnYoI6xIqlic2i882SoPnR2TEauKc9tQ,575
|
47
50
|
tests/examples/contracts/multi_file_contract/other.py,sha256=jHDtjUL3eAUgE6yOYKFw_RfAH7kIwk8CvxUjbWHNruk,236
|
51
|
+
tests/examples/tests/test_custom_validators.py,sha256=ounk3fBqDexAI3eRUqscMqKf5vz77tbSxW4Cz8tzfF0,2172
|
48
52
|
tests/examples/tests/test_football_prediction_market.py,sha256=f2hfDK76WrNJZtFkTPKoPRR6bkmFLEssnlwwltSnU9A,1111
|
49
53
|
tests/examples/tests/test_intelligent_oracle_factory.py,sha256=sL26aeb84XpJPCSUSIX3yrbwQE8GZtvNcsaKTpngFmY,7611
|
50
54
|
tests/examples/tests/test_invalid_deploy.py,sha256=pppM8_Vn4DXcWq9iyJXb0SpZnKXkIyJxoIDW5ApCS94,814
|
51
55
|
tests/examples/tests/test_llm_erc20.py,sha256=zb5F_7NgvZXhvqL2nULwzuTT6LGDprSy0WgrdjY7pZc,2096
|
52
|
-
tests/examples/tests/test_llm_erc20_analyze.py,sha256=
|
56
|
+
tests/examples/tests/test_llm_erc20_analyze.py,sha256=rVnC3iQW_1J3P6cczEVOOG84K6ldCzlZbMO9WXQdRds,1849
|
53
57
|
tests/examples/tests/test_log_indexer.py,sha256=46AqL7qquNc9GX2wxFxVcQXLqruMnPmxXl1yeB0-KZ4,2869
|
54
58
|
tests/examples/tests/test_multi_file_contract.py,sha256=1Emj6ze4f-OrpxvqExeJhPHjK0cNAQW54MXf6fy2Yuc,469
|
55
59
|
tests/examples/tests/test_multi_read_erc20.py,sha256=pSZUxoB33Z2EBtcvXxfUgwGSi_h7ryPoovkiNIfNAVQ,3713
|
56
60
|
tests/examples/tests/test_multi_tenant_storage.py,sha256=8B3tjnRbT8ATN5obtWkGsN3nOtBU9OSjuaH9aEat3vc,2935
|
57
61
|
tests/examples/tests/test_read_erc20.py,sha256=vLGQwguaNnT497nSq-vt4LrXj4ehn5ZSgfPt0GVFoPc,1254
|
62
|
+
tests/examples/tests/test_simple_time_contract.py,sha256=HQCJNheFyaHh73jZHyGOhNItzg045o8XsW-jLnNp-xc,3199
|
58
63
|
tests/examples/tests/test_storage.py,sha256=y46nPjM-Jd9FVJmaNE29RPqamzxVwYtPPWE_GlXUsls,774
|
59
64
|
tests/examples/tests/test_user_storage.py,sha256=wk0r0AXfKNgI7Eeyc8noNlJKvZBFXDbXTQE_u19XxBQ,2927
|
60
65
|
tests/examples/tests/test_wizard_of_coin.py,sha256=AOQTanDsfZt9zIGkqZass_4BsGcVKTHzqRejN4KhSPI,854
|
@@ -70,8 +75,8 @@ tests/gltest_cli/config/test_config_integration.py,sha256=vPTzr3_h9UMw7m72HogBJE
|
|
70
75
|
tests/gltest_cli/config/test_general_config.py,sha256=UHtSwVnso-ZwNtYM0Z4v2sCLKwyrVbHlk6b1leVfV84,14703
|
71
76
|
tests/gltest_cli/config/test_plugin.py,sha256=COrEK5tHP1BSzanWbZHmN3EQgE9VuTcPvB95pgOvKS4,7974
|
72
77
|
tests/gltest_cli/config/test_user.py,sha256=JxR655oUFoM9quWQO68CVPKRpT0TMpzS3bF6j6NWyT4,14401
|
73
|
-
genlayer_test-0.
|
74
|
-
genlayer_test-0.
|
75
|
-
genlayer_test-0.
|
76
|
-
genlayer_test-0.
|
77
|
-
genlayer_test-0.
|
78
|
+
genlayer_test-0.8.0.dist-info/METADATA,sha256=6LQF4o37U3qg9rmmLLoZps0XpC0T5gFsg_l4NZr7z4g,39178
|
79
|
+
genlayer_test-0.8.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
80
|
+
genlayer_test-0.8.0.dist-info/entry_points.txt,sha256=RWPcSArBpz_G4BYioh5L8Q8hyClRbSgzLimjcWMp-BQ,94
|
81
|
+
genlayer_test-0.8.0.dist-info/top_level.txt,sha256=-qiGZxTRBytujzgVcKpxjvQ-WNeUDjXa59ceGMwMpko,24
|
82
|
+
genlayer_test-0.8.0.dist-info/RECORD,,
|
gltest/__init__.py
CHANGED
@@ -8,6 +8,8 @@ from gltest.clients import (
|
|
8
8
|
get_gl_client,
|
9
9
|
)
|
10
10
|
from gltest.contracts import get_contract_factory
|
11
|
+
from gltest.validators import get_validator_factory
|
12
|
+
|
11
13
|
|
12
14
|
__all__ = [
|
13
15
|
"create_account",
|
@@ -16,4 +18,5 @@ __all__ = [
|
|
16
18
|
"get_gl_client",
|
17
19
|
"get_accounts",
|
18
20
|
"get_default_account",
|
21
|
+
"get_validator_factory",
|
19
22
|
]
|
gltest/contracts/contract.py
CHANGED
@@ -7,7 +7,9 @@ from gltest.types import (
|
|
7
7
|
GenLayerTransaction,
|
8
8
|
TransactionStatus,
|
9
9
|
TransactionHashVariant,
|
10
|
+
TransactionContext,
|
10
11
|
)
|
12
|
+
from genlayer_py.types import SimConfig
|
11
13
|
from typing import List, Any, Optional, Dict, Callable
|
12
14
|
from gltest_cli.config.general import get_general_config
|
13
15
|
from .contract_functions import ContractFunction
|
@@ -25,14 +27,24 @@ def read_contract_wrapper(
|
|
25
27
|
|
26
28
|
def call_method(
|
27
29
|
transaction_hash_variant: TransactionHashVariant = TransactionHashVariant.LATEST_NONFINAL,
|
30
|
+
transaction_context: Optional[TransactionContext] = None,
|
28
31
|
):
|
29
32
|
client = get_gl_client()
|
33
|
+
sim_config = None
|
34
|
+
if transaction_context:
|
35
|
+
try:
|
36
|
+
sim_config = SimConfig(**transaction_context)
|
37
|
+
except TypeError as e:
|
38
|
+
raise ValueError(
|
39
|
+
f"Invalid transaction_context keys: {sorted(transaction_context.keys())}"
|
40
|
+
) from e
|
30
41
|
return client.read_contract(
|
31
42
|
address=self.address,
|
32
43
|
function_name=method_name,
|
33
44
|
account=self.account,
|
34
45
|
args=args,
|
35
46
|
transaction_hash_variant=transaction_hash_variant,
|
47
|
+
sim_config=sim_config,
|
36
48
|
)
|
37
49
|
|
38
50
|
return ContractFunction(
|
@@ -59,6 +71,7 @@ def write_contract_wrapper(
|
|
59
71
|
wait_retries: Optional[int] = None,
|
60
72
|
wait_triggered_transactions: bool = False,
|
61
73
|
wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
|
74
|
+
transaction_context: Optional[TransactionContext] = None,
|
62
75
|
):
|
63
76
|
"""
|
64
77
|
Transact the contract method.
|
@@ -80,6 +93,14 @@ def write_contract_wrapper(
|
|
80
93
|
else False
|
81
94
|
)
|
82
95
|
client = get_gl_client()
|
96
|
+
sim_config = None
|
97
|
+
if transaction_context:
|
98
|
+
try:
|
99
|
+
sim_config = SimConfig(**transaction_context)
|
100
|
+
except TypeError as e:
|
101
|
+
raise ValueError(
|
102
|
+
f"Invalid transaction_context keys: {sorted(transaction_context.keys())}"
|
103
|
+
) from e
|
83
104
|
tx_hash = client.write_contract(
|
84
105
|
address=self.address,
|
85
106
|
function_name=method_name,
|
@@ -88,6 +109,7 @@ def write_contract_wrapper(
|
|
88
109
|
consensus_max_rotations=consensus_max_rotations,
|
89
110
|
leader_only=leader_only,
|
90
111
|
args=args,
|
112
|
+
sim_config=sim_config,
|
91
113
|
)
|
92
114
|
receipt = client.wait_for_transaction_receipt(
|
93
115
|
transaction_hash=tx_hash,
|
@@ -113,6 +135,7 @@ def write_contract_wrapper(
|
|
113
135
|
plugin: Optional[str] = None,
|
114
136
|
plugin_config: Optional[Dict[str, Any]] = None,
|
115
137
|
runs: int = 100,
|
138
|
+
genvm_datetime: Optional[str] = None,
|
116
139
|
):
|
117
140
|
"""
|
118
141
|
Analyze the contract method using StatsCollector.
|
@@ -129,6 +152,7 @@ def write_contract_wrapper(
|
|
129
152
|
config=config,
|
130
153
|
plugin=plugin,
|
131
154
|
plugin_config=plugin_config,
|
155
|
+
genvm_datetime=genvm_datetime,
|
132
156
|
)
|
133
157
|
sim_results = collector.run_simulations(sim_config, runs)
|
134
158
|
return collector.analyze_results(sim_results, runs, sim_config)
|
@@ -15,6 +15,7 @@ from gltest.clients import (
|
|
15
15
|
get_gl_hosted_studio_client,
|
16
16
|
get_local_client,
|
17
17
|
)
|
18
|
+
from genlayer_py.types import SimConfig
|
18
19
|
from .contract import Contract
|
19
20
|
from gltest.logging import logger
|
20
21
|
from gltest.types import TransactionStatus, GenLayerTransaction, CalldataEncodable
|
@@ -22,6 +23,7 @@ from gltest.assertions import tx_execution_failed
|
|
22
23
|
from gltest.exceptions import DeploymentError
|
23
24
|
from gltest_cli.config.general import get_general_config
|
24
25
|
from gltest.utils import extract_contract_address
|
26
|
+
from gltest.types import TransactionContext
|
25
27
|
|
26
28
|
|
27
29
|
@dataclass
|
@@ -113,6 +115,7 @@ class ContractFactory:
|
|
113
115
|
wait_transaction_status: TransactionStatus = TransactionStatus.ACCEPTED,
|
114
116
|
wait_triggered_transactions: bool = False,
|
115
117
|
wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
|
118
|
+
transaction_context: Optional[TransactionContext] = None,
|
116
119
|
) -> Contract:
|
117
120
|
"""
|
118
121
|
Deploy the contract and return a Contract instance (convenience method).
|
@@ -129,6 +132,7 @@ class ContractFactory:
|
|
129
132
|
wait_transaction_status=wait_transaction_status,
|
130
133
|
wait_triggered_transactions=wait_triggered_transactions,
|
131
134
|
wait_triggered_transactions_status=wait_triggered_transactions_status,
|
135
|
+
transaction_context=transaction_context,
|
132
136
|
)
|
133
137
|
|
134
138
|
if tx_execution_failed(receipt):
|
@@ -147,6 +151,7 @@ class ContractFactory:
|
|
147
151
|
wait_transaction_status: TransactionStatus = TransactionStatus.ACCEPTED,
|
148
152
|
wait_triggered_transactions: bool = False,
|
149
153
|
wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
|
154
|
+
transaction_context: Optional[TransactionContext] = None,
|
150
155
|
) -> GenLayerTransaction:
|
151
156
|
"""
|
152
157
|
Deploy the contract and return the transaction receipt.
|
@@ -170,12 +175,21 @@ class ContractFactory:
|
|
170
175
|
|
171
176
|
client = get_gl_client()
|
172
177
|
try:
|
178
|
+
sim_config = None
|
179
|
+
if transaction_context:
|
180
|
+
try:
|
181
|
+
sim_config = SimConfig(**transaction_context)
|
182
|
+
except TypeError as e:
|
183
|
+
raise ValueError(
|
184
|
+
f"Invalid transaction_context keys: {sorted(transaction_context.keys())}"
|
185
|
+
) from e
|
173
186
|
tx_hash = client.deploy_contract(
|
174
187
|
code=self.contract_code,
|
175
188
|
args=args,
|
176
189
|
account=account,
|
177
190
|
consensus_max_rotations=consensus_max_rotations,
|
178
191
|
leader_only=leader_only,
|
192
|
+
sim_config=sim_config,
|
179
193
|
)
|
180
194
|
tx_receipt = client.wait_for_transaction_receipt(
|
181
195
|
transaction_hash=tx_hash,
|
@@ -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, TransactionHashVariant
|
3
|
+
from gltest.types import TransactionStatus, TransactionHashVariant, TransactionContext
|
4
4
|
|
5
5
|
|
6
6
|
@dataclass
|
@@ -14,10 +14,14 @@ class ContractFunction:
|
|
14
14
|
def call(
|
15
15
|
self,
|
16
16
|
transaction_hash_variant: TransactionHashVariant = TransactionHashVariant.LATEST_NONFINAL,
|
17
|
+
transaction_context: Optional[TransactionContext] = None,
|
17
18
|
):
|
18
19
|
if not self.read_only:
|
19
20
|
raise ValueError("call() not implemented for non-readonly method")
|
20
|
-
return self.call_method(
|
21
|
+
return self.call_method(
|
22
|
+
transaction_hash_variant=transaction_hash_variant,
|
23
|
+
transaction_context=transaction_context,
|
24
|
+
)
|
21
25
|
|
22
26
|
def transact(
|
23
27
|
self,
|
@@ -28,6 +32,7 @@ class ContractFunction:
|
|
28
32
|
wait_retries: Optional[int] = None,
|
29
33
|
wait_triggered_transactions: bool = False,
|
30
34
|
wait_triggered_transactions_status: TransactionStatus = TransactionStatus.ACCEPTED,
|
35
|
+
transaction_context: Optional[TransactionContext] = None,
|
31
36
|
):
|
32
37
|
if self.read_only:
|
33
38
|
raise ValueError("Cannot transact read-only method")
|
@@ -39,6 +44,7 @@ class ContractFunction:
|
|
39
44
|
wait_retries=wait_retries,
|
40
45
|
wait_triggered_transactions=wait_triggered_transactions,
|
41
46
|
wait_triggered_transactions_status=wait_triggered_transactions_status,
|
47
|
+
transaction_context=transaction_context,
|
42
48
|
)
|
43
49
|
|
44
50
|
def analyze(
|
@@ -49,6 +55,7 @@ class ContractFunction:
|
|
49
55
|
plugin: Optional[str] = None,
|
50
56
|
plugin_config: Optional[Dict[str, Any]] = None,
|
51
57
|
runs: int = 100,
|
58
|
+
genvm_datetime: Optional[str] = None,
|
52
59
|
):
|
53
60
|
if self.read_only:
|
54
61
|
raise ValueError("Cannot analyze read-only method")
|
@@ -59,4 +66,5 @@ class ContractFunction:
|
|
59
66
|
plugin=plugin,
|
60
67
|
plugin_config=plugin_config,
|
61
68
|
runs=runs,
|
69
|
+
genvm_datetime=genvm_datetime,
|
62
70
|
)
|
@@ -29,6 +29,7 @@ class SimulationConfig:
|
|
29
29
|
config: Optional[Dict[str, Any]] = None
|
30
30
|
plugin: Optional[str] = None
|
31
31
|
plugin_config: Optional[Dict[str, Any]] = None
|
32
|
+
genvm_datetime: Optional[str] = None
|
32
33
|
|
33
34
|
|
34
35
|
@dataclass
|
@@ -103,7 +104,12 @@ class StatsCollector:
|
|
103
104
|
self, sim_config: SimulationConfig
|
104
105
|
) -> Dict[str, Any]:
|
105
106
|
"""Execute a single simulation."""
|
106
|
-
config_dict = {
|
107
|
+
config_dict = {}
|
108
|
+
|
109
|
+
if sim_config.genvm_datetime is not None:
|
110
|
+
config_dict["genvm_datetime"] = sim_config.genvm_datetime
|
111
|
+
|
112
|
+
validator_info = {
|
107
113
|
"provider": sim_config.provider,
|
108
114
|
"model": sim_config.model,
|
109
115
|
}
|
@@ -113,9 +119,10 @@ class StatsCollector:
|
|
113
119
|
and sim_config.plugin is not None
|
114
120
|
and sim_config.plugin_config is not None
|
115
121
|
):
|
116
|
-
|
117
|
-
|
118
|
-
|
122
|
+
validator_info["config"] = sim_config.config
|
123
|
+
validator_info["plugin"] = sim_config.plugin
|
124
|
+
validator_info["plugin_config"] = sim_config.plugin_config
|
125
|
+
config_dict["validators"] = [validator_info]
|
119
126
|
|
120
127
|
return self.client.simulate_write_contract(
|
121
128
|
address=self.contract_address,
|
gltest/types.py
CHANGED
@@ -6,3 +6,32 @@ from genlayer_py.types import (
|
|
6
6
|
CalldataEncodable,
|
7
7
|
TransactionHashVariant,
|
8
8
|
)
|
9
|
+
from typing import List, TypedDict, Dict, Any
|
10
|
+
|
11
|
+
|
12
|
+
class MockedLLMResponse(TypedDict):
|
13
|
+
"""Maps prompts to responses"""
|
14
|
+
|
15
|
+
# Prompt -> raw JSON string response
|
16
|
+
nondet_exec_prompt: Dict[str, str]
|
17
|
+
|
18
|
+
# Principle -> expected boolean
|
19
|
+
eq_principle_prompt_comparative: Dict[str, bool]
|
20
|
+
eq_principle_prompt_non_comparative: Dict[str, bool]
|
21
|
+
|
22
|
+
|
23
|
+
class ValidatorConfig(TypedDict):
|
24
|
+
"""Validator information."""
|
25
|
+
|
26
|
+
provider: str
|
27
|
+
model: str
|
28
|
+
config: Dict[str, Any]
|
29
|
+
plugin: str
|
30
|
+
plugin_config: Dict[str, Any]
|
31
|
+
|
32
|
+
|
33
|
+
class TransactionContext(TypedDict, total=False):
|
34
|
+
"""Context for transaction operations."""
|
35
|
+
|
36
|
+
validators: List[ValidatorConfig] # List to create virtual validators
|
37
|
+
genvm_datetime: str # ISO format datetime string
|
@@ -0,0 +1,136 @@
|
|
1
|
+
from gltest.types import MockedLLMResponse
|
2
|
+
from dataclasses import dataclass
|
3
|
+
from typing import Dict, Any, Optional, List
|
4
|
+
from copy import deepcopy
|
5
|
+
|
6
|
+
|
7
|
+
@dataclass
|
8
|
+
class Validator:
|
9
|
+
stake: int
|
10
|
+
provider: str
|
11
|
+
model: str
|
12
|
+
config: Dict[str, Any]
|
13
|
+
plugin: str
|
14
|
+
plugin_config: Dict[str, Any]
|
15
|
+
|
16
|
+
# Mock configuration
|
17
|
+
mock_enabled: bool
|
18
|
+
mock_llm_response: Optional[MockedLLMResponse]
|
19
|
+
|
20
|
+
def to_dict(self) -> Dict[str, Any]:
|
21
|
+
normal_config = {
|
22
|
+
"stake": self.stake,
|
23
|
+
"provider": self.provider,
|
24
|
+
"model": self.model,
|
25
|
+
"config": deepcopy(self.config),
|
26
|
+
"plugin": self.plugin,
|
27
|
+
"plugin_config": deepcopy(self.plugin_config),
|
28
|
+
}
|
29
|
+
if not self.mock_enabled:
|
30
|
+
return normal_config
|
31
|
+
|
32
|
+
mock = self.mock_llm_response or {}
|
33
|
+
mock_config = {
|
34
|
+
"response": mock.get("nondet_exec_prompt", {}),
|
35
|
+
"eq_principle_prompt_comparative": mock.get(
|
36
|
+
"eq_principle_prompt_comparative", {}
|
37
|
+
),
|
38
|
+
"eq_principle_prompt_non_comparative": mock.get(
|
39
|
+
"eq_principle_prompt_non_comparative", {}
|
40
|
+
),
|
41
|
+
}
|
42
|
+
return {
|
43
|
+
**normal_config,
|
44
|
+
"plugin_config": {
|
45
|
+
**self.plugin_config,
|
46
|
+
"mock_response": mock_config,
|
47
|
+
},
|
48
|
+
}
|
49
|
+
|
50
|
+
def batch_clone(self, count: int) -> List["Validator"]:
|
51
|
+
return [self.clone() for _ in range(count)]
|
52
|
+
|
53
|
+
def clone(self) -> "Validator":
|
54
|
+
return Validator(
|
55
|
+
stake=self.stake,
|
56
|
+
provider=self.provider,
|
57
|
+
model=self.model,
|
58
|
+
config=deepcopy(self.config),
|
59
|
+
plugin=self.plugin,
|
60
|
+
plugin_config=deepcopy(self.plugin_config),
|
61
|
+
mock_enabled=self.mock_enabled,
|
62
|
+
mock_llm_response=deepcopy(self.mock_llm_response),
|
63
|
+
)
|
64
|
+
|
65
|
+
|
66
|
+
class ValidatorFactory:
|
67
|
+
def __init__(self):
|
68
|
+
pass
|
69
|
+
|
70
|
+
def create_validator(
|
71
|
+
self,
|
72
|
+
stake: int,
|
73
|
+
provider: str,
|
74
|
+
model: str,
|
75
|
+
config: Dict[str, Any],
|
76
|
+
plugin: str,
|
77
|
+
plugin_config: Dict[str, Any],
|
78
|
+
) -> Validator:
|
79
|
+
return Validator(
|
80
|
+
stake=stake,
|
81
|
+
provider=provider,
|
82
|
+
model=model,
|
83
|
+
config=deepcopy(config),
|
84
|
+
plugin=plugin,
|
85
|
+
plugin_config=deepcopy(plugin_config),
|
86
|
+
mock_enabled=False,
|
87
|
+
mock_llm_response=None,
|
88
|
+
)
|
89
|
+
|
90
|
+
def batch_create_validators(
|
91
|
+
self,
|
92
|
+
count: int,
|
93
|
+
stake: int,
|
94
|
+
provider: str,
|
95
|
+
model: str,
|
96
|
+
config: Dict[str, Any],
|
97
|
+
plugin: str,
|
98
|
+
plugin_config: Dict[str, Any],
|
99
|
+
) -> List[Validator]:
|
100
|
+
return [
|
101
|
+
self.create_validator(
|
102
|
+
stake=stake,
|
103
|
+
provider=provider,
|
104
|
+
model=model,
|
105
|
+
config=config,
|
106
|
+
plugin=plugin,
|
107
|
+
plugin_config=plugin_config,
|
108
|
+
)
|
109
|
+
for _ in range(count)
|
110
|
+
]
|
111
|
+
|
112
|
+
def create_mock_validator(self, mock_llm_response: MockedLLMResponse) -> Validator:
|
113
|
+
return Validator(
|
114
|
+
stake=8,
|
115
|
+
provider="openai",
|
116
|
+
model="gpt-4o",
|
117
|
+
config={"temperature": 0.75, "max_tokens": 500},
|
118
|
+
plugin="openai-compatible",
|
119
|
+
plugin_config={
|
120
|
+
"api_key_env_var": "OPENAIKEY",
|
121
|
+
"api_url": "https://api.openai.com",
|
122
|
+
},
|
123
|
+
mock_enabled=True,
|
124
|
+
mock_llm_response=deepcopy(mock_llm_response),
|
125
|
+
)
|
126
|
+
|
127
|
+
def batch_create_mock_validators(
|
128
|
+
self,
|
129
|
+
count: int,
|
130
|
+
mock_llm_response: MockedLLMResponse,
|
131
|
+
) -> List[Validator]:
|
132
|
+
return [self.create_mock_validator(mock_llm_response) for _ in range(count)]
|
133
|
+
|
134
|
+
|
135
|
+
def get_validator_factory() -> ValidatorFactory:
|
136
|
+
return ValidatorFactory()
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# {
|
2
|
+
# "Seq": [
|
3
|
+
# { "Depends": "py-lib-genlayer-embeddings:09h0i209wrzh4xzq86f79c60x0ifs7xcjwl53ysrnw06i54ddxyi" },
|
4
|
+
# { "Depends": "py-genlayer:1j12s63yfjpva9ik2xgnffgrs6v44y1f52jvj9w7xvdn7qckd379" }
|
5
|
+
# ]
|
6
|
+
# }
|
7
|
+
|
8
|
+
from datetime import datetime, timezone
|
9
|
+
from genlayer import *
|
10
|
+
|
11
|
+
|
12
|
+
class SimpleTimeContract(gl.Contract):
|
13
|
+
"""
|
14
|
+
A simple contract that demonstrates time-based function availability.
|
15
|
+
"""
|
16
|
+
|
17
|
+
start_date: str # ISO format datetime string
|
18
|
+
data: str
|
19
|
+
is_active: bool
|
20
|
+
|
21
|
+
def __init__(self, start_datetime_iso: str):
|
22
|
+
"""
|
23
|
+
Initialize the contract with a required start date (ISO 8601).
|
24
|
+
"""
|
25
|
+
self.start_date = start_datetime_iso
|
26
|
+
self.is_active = False
|
27
|
+
self.data = ""
|
28
|
+
|
29
|
+
def _days_since_start(self) -> int:
|
30
|
+
"""Calculate days elapsed since start date."""
|
31
|
+
current = datetime.now(timezone.utc)
|
32
|
+
start = datetime.fromisoformat(self.start_date)
|
33
|
+
print(f"Current: {current}, Start: {start}")
|
34
|
+
delta = current - start
|
35
|
+
print(f"Delta: {delta}")
|
36
|
+
return delta.days
|
37
|
+
|
38
|
+
@gl.public.write
|
39
|
+
def activate(self):
|
40
|
+
"""
|
41
|
+
Activate the contract.
|
42
|
+
Only works if current date is after start date.
|
43
|
+
"""
|
44
|
+
days = self._days_since_start()
|
45
|
+
|
46
|
+
if days < 0:
|
47
|
+
raise ValueError(
|
48
|
+
f"Cannot activate before start date. Days until start: {abs(days)}"
|
49
|
+
)
|
50
|
+
|
51
|
+
self.is_active = True
|
52
|
+
|
53
|
+
@gl.public.write
|
54
|
+
def set_data(self, value: str):
|
55
|
+
"""
|
56
|
+
Set data in the contract.
|
57
|
+
Only works if contract is active and within 30 days of start.
|
58
|
+
"""
|
59
|
+
if not self.is_active:
|
60
|
+
raise ValueError("Contract must be activated first")
|
61
|
+
|
62
|
+
days = self._days_since_start()
|
63
|
+
|
64
|
+
if days > 30:
|
65
|
+
raise ValueError(
|
66
|
+
f"Function expired. Was available for 30 days after start, now at day {days}"
|
67
|
+
)
|
68
|
+
|
69
|
+
self.data = value
|
70
|
+
|
71
|
+
@gl.public.view
|
72
|
+
def get_status(self) -> dict:
|
73
|
+
"""Get current contract status."""
|
74
|
+
days = self._days_since_start()
|
75
|
+
current = datetime.now(timezone.utc)
|
76
|
+
|
77
|
+
return {
|
78
|
+
"start_date": self.start_date,
|
79
|
+
"current_time": current.isoformat(),
|
80
|
+
"days_since_start": days,
|
81
|
+
"is_active": self.is_active,
|
82
|
+
"data": self.data,
|
83
|
+
"can_activate": days >= 0 and not self.is_active,
|
84
|
+
"can_set_data": self.is_active and 0 <= days <= 30,
|
85
|
+
}
|
@@ -0,0 +1,65 @@
|
|
1
|
+
from gltest import get_contract_factory
|
2
|
+
from gltest.assertions import tx_execution_succeeded
|
3
|
+
from gltest import get_validator_factory
|
4
|
+
from gltest.types import MockedLLMResponse
|
5
|
+
import json
|
6
|
+
|
7
|
+
|
8
|
+
def test_custom_validators():
|
9
|
+
|
10
|
+
validator_factory = get_validator_factory()
|
11
|
+
validators = validator_factory.batch_create_validators(
|
12
|
+
count=5,
|
13
|
+
stake=8,
|
14
|
+
provider="openai",
|
15
|
+
model="gpt-4o",
|
16
|
+
config={"temperature": 0.75, "max_tokens": 500},
|
17
|
+
plugin="openai-compatible",
|
18
|
+
plugin_config={
|
19
|
+
"api_key_env_var": "OPENAIKEY",
|
20
|
+
"api_url": "https://api.openai.com",
|
21
|
+
},
|
22
|
+
)
|
23
|
+
|
24
|
+
factory = get_contract_factory("WizardOfCoin")
|
25
|
+
contract = factory.deploy(
|
26
|
+
args=[True],
|
27
|
+
transaction_context={"validators": [v.to_dict() for v in validators]},
|
28
|
+
)
|
29
|
+
|
30
|
+
transaction_response_call_1 = contract.ask_for_coin(
|
31
|
+
args=["Can you please give me my coin?"]
|
32
|
+
).transact(transaction_context={"validators": [v.to_dict() for v in validators]})
|
33
|
+
assert tx_execution_succeeded(transaction_response_call_1)
|
34
|
+
|
35
|
+
|
36
|
+
def test_custom_mocked_validators():
|
37
|
+
mock_llm_response: MockedLLMResponse = {
|
38
|
+
"nondet_exec_prompt": {
|
39
|
+
"wizard": json.dumps(
|
40
|
+
{
|
41
|
+
"reasoning": "I am a grumpy wizard and I never give away my coins!",
|
42
|
+
"give_coin": False,
|
43
|
+
}
|
44
|
+
),
|
45
|
+
},
|
46
|
+
"eq_principle_prompt_comparative": {
|
47
|
+
"The value of give_coin has to match": True
|
48
|
+
},
|
49
|
+
}
|
50
|
+
validator_factory = get_validator_factory()
|
51
|
+
validators = validator_factory.batch_create_mock_validators(
|
52
|
+
count=5,
|
53
|
+
mock_llm_response=mock_llm_response,
|
54
|
+
)
|
55
|
+
|
56
|
+
factory = get_contract_factory("WizardOfCoin")
|
57
|
+
contract = factory.deploy(
|
58
|
+
args=[True],
|
59
|
+
transaction_context={"validators": [v.to_dict() for v in validators]},
|
60
|
+
)
|
61
|
+
|
62
|
+
transaction_response_call_1 = contract.ask_for_coin(
|
63
|
+
args=["Can you please give me my coin?"]
|
64
|
+
).transact(transaction_context={"validators": [v.to_dict() for v in validators]})
|
65
|
+
assert tx_execution_succeeded(transaction_response_call_1)
|
@@ -1,4 +1,5 @@
|
|
1
1
|
from gltest import get_contract_factory, get_default_account, create_account
|
2
|
+
from datetime import datetime, timezone
|
2
3
|
|
3
4
|
|
4
5
|
TOKEN_TOTAL_SUPPLY = 1000
|
@@ -21,7 +22,10 @@ def test_llm_erc20_analyze(setup_validators):
|
|
21
22
|
|
22
23
|
# Transfer from User A to User B
|
23
24
|
stats = contract.transfer(args=[TRANSFER_AMOUNT, from_account_b.address]).analyze(
|
24
|
-
provider="openai",
|
25
|
+
provider="openai",
|
26
|
+
model="gpt-4o",
|
27
|
+
runs=3,
|
28
|
+
genvm_datetime=datetime.now(timezone.utc).isoformat(),
|
25
29
|
)
|
26
30
|
|
27
31
|
# Verify it's a MethodStatsSummary object
|
@@ -0,0 +1,90 @@
|
|
1
|
+
from gltest import get_contract_factory
|
2
|
+
from datetime import datetime, timedelta, timezone
|
3
|
+
from gltest.assertions import tx_execution_succeeded, tx_execution_failed
|
4
|
+
|
5
|
+
|
6
|
+
def test_simple_time_contract():
|
7
|
+
"""Test all time-based functionality in a single comprehensive test."""
|
8
|
+
|
9
|
+
factory = get_contract_factory("SimpleTimeContract")
|
10
|
+
|
11
|
+
# Test 1: Deploy with past start date (10 days ago)
|
12
|
+
now = datetime.now(timezone.utc)
|
13
|
+
past_date = (now - timedelta(days=10)).isoformat()
|
14
|
+
contract = factory.deploy(args=[past_date])
|
15
|
+
|
16
|
+
# Test 1: Check initial status (10 days after start)
|
17
|
+
status = contract.get_status().call()
|
18
|
+
assert status["is_active"] == False
|
19
|
+
assert status["days_since_start"] == 10
|
20
|
+
assert status["can_activate"] == True
|
21
|
+
|
22
|
+
# Test 2: Try to activate before start date (simulate going back in time)
|
23
|
+
before_start_date = now - timedelta(days=15) # 5 days before start
|
24
|
+
before_start_date_receipt = contract.activate().transact(
|
25
|
+
transaction_context={
|
26
|
+
"genvm_datetime": before_start_date.isoformat(),
|
27
|
+
},
|
28
|
+
)
|
29
|
+
assert tx_execution_failed(before_start_date_receipt)
|
30
|
+
|
31
|
+
# Test 3: Activate after start date
|
32
|
+
activate_date = now - timedelta(days=5) # 5 days after start (15 days ago + 10)
|
33
|
+
activate_receipt = contract.activate().transact(
|
34
|
+
transaction_context={
|
35
|
+
"genvm_datetime": activate_date.isoformat(),
|
36
|
+
},
|
37
|
+
)
|
38
|
+
assert tx_execution_succeeded(activate_receipt)
|
39
|
+
|
40
|
+
# Test 4: Verify activation and check status
|
41
|
+
status = contract.get_status().call(
|
42
|
+
transaction_context={
|
43
|
+
"genvm_datetime": activate_date.isoformat(),
|
44
|
+
},
|
45
|
+
)
|
46
|
+
assert status["is_active"] == True
|
47
|
+
assert status["days_since_start"] == 5
|
48
|
+
assert status["can_set_data"] == True
|
49
|
+
|
50
|
+
# Test 5: Set data within valid period (within 30 days)
|
51
|
+
set_data_date = now - timedelta(days=2) # 8 days after start
|
52
|
+
test_data = "Test data within valid period"
|
53
|
+
set_data_receipt = contract.set_data(
|
54
|
+
args=[test_data],
|
55
|
+
).transact(
|
56
|
+
transaction_context={
|
57
|
+
"genvm_datetime": set_data_date.isoformat(),
|
58
|
+
}
|
59
|
+
)
|
60
|
+
assert tx_execution_succeeded(set_data_receipt)
|
61
|
+
|
62
|
+
# Test 6: Verify data was set
|
63
|
+
status = contract.get_status().call(
|
64
|
+
transaction_context={
|
65
|
+
"genvm_datetime": set_data_date.isoformat(),
|
66
|
+
},
|
67
|
+
)
|
68
|
+
assert status["data"] == test_data
|
69
|
+
assert status["days_since_start"] == 8
|
70
|
+
|
71
|
+
# Test 7: Try to set data after 30 days (should fail)
|
72
|
+
expired_date = now + timedelta(days=25) # 35 days after start
|
73
|
+
expired_date_receipt = contract.set_data(
|
74
|
+
args=["Should fail - expired"],
|
75
|
+
).transact(
|
76
|
+
transaction_context={
|
77
|
+
"genvm_datetime": expired_date.isoformat(),
|
78
|
+
}
|
79
|
+
)
|
80
|
+
assert tx_execution_failed(expired_date_receipt)
|
81
|
+
|
82
|
+
# Test 8: Check status shows expired
|
83
|
+
status = contract.get_status().call(
|
84
|
+
transaction_context={
|
85
|
+
"genvm_datetime": expired_date.isoformat(),
|
86
|
+
},
|
87
|
+
)
|
88
|
+
assert status["is_active"] == True # Still active
|
89
|
+
assert status["can_set_data"] == False # But can't set data
|
90
|
+
assert status["days_since_start"] == 35
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|