Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 13 additions & 5 deletions pages/api-references/genlayer-py.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,14 @@ Waits for a transaction receipt.
receipt = client.wait_for_transaction_receipt(
transaction_hash=transaction_hash,
status='FINALIZED', # or 'ACCEPTED'
full_transaction=False, # Optional: False for simplified receipt, True for complete
)
```

**Parameters:**
- `transaction_hash`: The transaction hash
- `status`: The desired transaction status ('FINALIZED' or 'ACCEPTED')
- `full_transaction`: (Optional) `False` (default) returns a simplified receipt with binary data removed; `True` returns the complete receipt with all fields

**Returns:** Transaction receipt object

Expand All @@ -65,8 +67,9 @@ Reads data from a deployed contract.
```python
result = client.read_contract(
address=contract_address,
function_name: 'get_complete_storage',
args: [],
function_name='get_complete_storage',
args=[],
state_status='accepted', # Optional: 'accepted' or 'finalized'
)
```

Expand All @@ -75,6 +78,7 @@ result = client.read_contract(
- `address`: The contract address
- `function_name`: The name of the function to call
- `args`: An array of arguments for the function call
- `state_status`: (Optional) The state to query against (`'accepted'` or `'finalized'`)

**Returns:** The result of the contract function call
<br/>
Expand Down Expand Up @@ -132,11 +136,15 @@ account_with_key = create_account('0x1234...') # Replace with actual private key

## Chain Information

### localnet
### Available Chains

Provides configuration for the local GenLayer Studio chain.
```python
from genlayer_py.chains import localnet
from genlayer_py.chains import localnet, studionet, testnet_asimov
```

- **localnet**: Local development network (GenLayer Studio)
- **studionet**: Hosted development environment
- **testnet_asimov**: Public test network

**Usage:** Used when creating a client to specify the chain

94 changes: 89 additions & 5 deletions pages/api-references/genlayer-test.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,88 @@ For comprehensive test examples and implementation patterns, see our [Test Suite
pip install genlayer-test
```

## Two Testing Modes

The testing suite provides two execution modes:

| | Direct Mode | Studio Mode |
|---|---|---|
| **How it works** | Runs contract Python code directly in-memory | Deploys to GenLayer Studio, interacts via RPC |
| **Speed** | ~milliseconds per test | ~minutes per test |
| **Prerequisites** | Python >= 3.12 | Python >= 3.12 + GenLayer Studio (Docker) |
| **Best for** | Unit tests, rapid development, CI/CD | Integration tests, consensus validation, testnet |

**Start with Direct Mode** — it's faster, simpler, and doesn't require Docker. Use Studio Mode when you need full network behavior or multi-validator consensus.

## Direct Mode

Run contracts directly in Python — no simulator, no Docker, no network. Tests execute in milliseconds.

### Quick Start

```python
def test_storage(direct_vm, direct_deploy):
# Deploy contract in-memory
storage = direct_deploy("contracts/Storage.py", "initial")

# Read state directly
assert storage.get_storage() == "initial"

# Write state directly
storage.update_storage("updated")
assert storage.get_storage() == "updated"
```

Run with pytest:

```bash
pytest tests/ -v
```

### Direct Mode Fixtures

| Fixture | Description |
|---------|-------------|
| `direct_vm` | VM context with cheatcodes |
| `direct_deploy` | Deploy contracts directly |
| `direct_alice`, `direct_bob`, `direct_charlie` | Test addresses |
| `direct_owner` | Default sender address |
| `direct_accounts` | List of 10 test addresses |

### Cheatcodes

```python
# Change sender
direct_vm.sender = alice

# Prank (temporary sender change)
with direct_vm.prank(bob):
contract.method() # Called as bob

# Snapshots (captures full state: storage, mocks, sender, validators)
snap_id = direct_vm.snapshot()
contract.modify_state()
direct_vm.revert(snap_id) # Full state restored

# Expect revert
with direct_vm.expect_revert("Insufficient balance"):
contract.transfer(bob, 1000000)

Comment on lines +63 to +79
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's check the file exists and see its structure
wc -l pages/api-references/genlayer-test.mdx

Repository: genlayerlabs/genlayer-docs

Length of output: 112


🏁 Script executed:

# Check the specific lines mentioned (63-79) and surrounding context
sed -n '55,85p' pages/api-references/genlayer-test.mdx

Repository: genlayerlabs/genlayer-docs

Length of output: 1049


🏁 Script executed:

# Search for fixture definitions in the file
rg -n "direct_alice|direct_bob|fixtures|alice|bob" pages/api-references/genlayer-test.mdx | head -40

Repository: genlayerlabs/genlayer-docs

Length of output: 495


Cheatcodes example uses undefined fixture names.

Lines 65, 68, and 78 use alice and bob, but the documented fixtures are direct_alice and direct_bob. The code snippet needs to use the correct fixture names to be runnable.

Required fix
 # Change sender
-direct_vm.sender = alice
+direct_vm.sender = direct_alice

 # Prank (temporary sender change)
-with direct_vm.prank(bob):
-    contract.method()  # Called as bob
+with direct_vm.prank(direct_bob):
+    contract.method()  # Called as direct_bob

 # Snapshots (captures full state: storage, mocks, sender, validators)
 snap_id = direct_vm.snapshot()
 contract.modify_state()
 direct_vm.revert(snap_id)  # Full state restored

 # Expect revert
 with direct_vm.expect_revert("Insufficient balance"):
-    contract.transfer(bob, 1000000)
+    contract.transfer(direct_bob, 1000000)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pages/api-references/genlayer-test.mdx` around lines 63 - 79, The snippet
uses undefined fixtures alice and bob; update all occurrences to the documented
fixtures direct_alice and direct_bob so the examples using direct_vm.sender,
direct_vm.prank, and direct_vm.expect_revert work; specifically replace alice ->
direct_alice and bob -> direct_bob in the lines that set direct_vm.sender, the
with direct_vm.prank(...) block, and the contract.transfer call as well as any
comments referencing those fixture names.

# Mock web/LLM (regex pattern matching)
direct_vm.mock_web(r"api\.example\.com", {"status": 200, "body": "{}"})
direct_vm.mock_llm(r"analyze.*", "positive sentiment")

# Test validator consensus logic
contract.update_price() # Runs leader_fn, captures validator
direct_vm.clear_mocks() # Swap mocks for validator
direct_vm.mock_llm(r".*", "different result")
assert direct_vm.run_validator() is False # Validator disagrees
```

## Studio Mode

The rest of this document covers Studio Mode — deploying contracts to a running GenLayer Studio instance and interacting via RPC.

## Configuration

The GenLayer Testing Suite can be configured using an optional `gltest.config.yaml` file in your project root. While not required, this file helps manage network configurations, contract paths, and environment settings.
Expand Down Expand Up @@ -493,7 +575,7 @@ The Mock LLM system allows you to simulate Large Language Model responses in Gen

```python
mock_response = {
"response": {}, # Optional: mocks gl.nondet.exec_prompt
"nondet_exec_prompt": {}, # Optional: mocks gl.nondet.exec_prompt
"eq_principle_prompt_comparative": {}, # Optional: mocks gl.eq_principle.prompt_comparative
"eq_principle_prompt_non_comparative": {} # Optional: mocks gl.eq_principle.prompt_non_comparative
}
Expand All @@ -503,9 +585,11 @@ setup_validators(mock_response)

### Method Mappings

- "response" -> gl.nondet.exec_prompt
- "eq_principle_prompt_comparative" -> gl.eq_principle.prompt_comparative
- "eq_principle_prompt_non_comparative" -> gl.eq_principle.prompt_non_comparative
| Mock Key | GenLayer Method |
|----------|----------------|
| `"nondet_exec_prompt"` | `gl.nondet.exec_prompt` |
| `"eq_principle_prompt_comparative"` | `gl.eq_principle.prompt_comparative` |
| `"eq_principle_prompt_non_comparative"` | `gl.eq_principle.prompt_non_comparative` |

### How It Works

Expand Down Expand Up @@ -534,7 +618,7 @@ from gltest import get_contract_factory

def test_with_mocked_llm(setup_validators):
mock_response = {
"response": {
"nondet_exec_prompt": {
"What is the weather?": "It's sunny today",
"Calculate 2+2": "4"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ It provides an interactive environment that serves as a comprehensive sandbox fo
The platform runs a simulated network with customizable validators that accurately mirror the GenLayer consensus mechanism. This feature allows developers to test their contracts under conditions that closely resemble the actual blockchain environment, ensuring reliable deployment outcomes.

### Getting Started:
1. **Set Up the Studio**: Developers initialize the Studio using `genlayer cli` command `genlayer init` which configures the environment and spawns a local validator network. GenLayer Studio is also available as a hosted instace at [studio.genlayer.com](https://studio.genlayer.com/).
2. **Write Your First Contract**: Intelligent Contracts in GenLayer are written in Python, utilizing its extensive libraries and GenVM capabilities like LLM calls and web integration. Refer to [Your First Contract](/developers/intelligent-contracts/your-first-contract) guide for more information.
1. **Set Up the Studio**: Developers initialize the Studio using `genlayer cli` command `genlayer init` which configures the environment and spawns a local validator network. GenLayer Studio is also available as a hosted instance at [studio.genlayer.com](https://studio.genlayer.com/).
2. **Write Your First Contract**: Intelligent Contracts in GenLayer are written in Python, utilizing its extensive libraries and GenVM capabilities like LLM calls and web integration. Refer to [Your First Contract](/developers/intelligent-contracts/first-contract) guide for more information.
3. **Deploy and Test**: Deploy your Intelligent Contracts through the Studio interface and test them in the simulated network.

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,4 +78,4 @@ You can find the GenLayerJS SDK repository on GitHub:

## Full Reference

The full reference for the GenLayerJS SDK is available in the [GenLayerJS SDK Reference](/references/genlayer-js).
The full reference for the GenLayerJS SDK is available in the [GenLayerJS SDK Reference](/api-references/genlayer-js).
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ class FetchGitHubProfile(gl.Contract):
github_profile_url = "https://github.com/"+github_handle

def fetch_github_profile_page_content() -> str:
return gl.get_webpage(github_profile_url, mode="text")
return gl.nondet.web.render(github_profile_url, mode="text")

self.github_profile = gl.eq_principle_strict_eq(fetch_github_profile_page_content)
self.github_profile = gl.eq_principle.strict_eq(fetch_github_profile_page_content)

@gl.public.view
def show_github_profile(self) -> str:
Expand All @@ -35,14 +35,14 @@ class FetchGitHubProfile(gl.Contract):
- **Write Method**:
- `fetch_github_profile(github_handle)` takes a GitHub username and retrieves their profile content.
- Constructs the profile URL using the provided handle.
- Uses `gl.eq_principle_strict_eq()` to ensure all nodes agree on the same profile content.
- Uses `gl.eq_principle.strict_eq()` to ensure all nodes agree on the same profile content.
- **Read Method**:
- `show_github_profile()` returns the stored profile content.

## Key Components

1. **GitHub Integration**: The contract uses `gl.get_webpage()` to fetch content from GitHub profiles.
2. **Deterministic Execution**: `gl.eq_principle_strict_eq()` ensures that all nodes in the network arrive at the same exact content.
1. **GitHub Integration**: The contract uses `gl.nondet.web.render()` to fetch content from GitHub profiles.
2. **Deterministic Execution**: `gl.eq_principle.strict_eq()` ensures that all nodes in the network arrive at the same exact content.
3. **State Management**: The contract maintains a single string state variable that stores the profile content.

## Deploying the Contract
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ class FetchWebContent(gl.Contract):
def fetch_web_content(self) -> typing.Any:

def fetch_web_url_content() -> str:
return gl.get_webpage("https://example.com/", mode="text")
return gl.nondet.web.render("https://example.com/", mode="text")

self.content = gl.eq_principle_strict_eq(fetch_web_url_content)
self.content = gl.eq_principle.strict_eq(fetch_web_url_content)

@gl.public.view
def show_content(self) -> str:
Expand All @@ -33,15 +33,15 @@ class FetchWebContent(gl.Contract):
- **Initialization**: The `FetchWebContent` class initializes with an empty string in the `content` variable.
- **Write Method**:
- `fetch_web_content()` retrieves content from a web page and stores it.
- It contains an inner function `fetch_web_url_content()` that uses `gl.get_webpage()` to fetch content.
- Uses `gl.eq_principle_strict_eq()` to ensure all nodes agree on the same content.
- It contains an inner function `fetch_web_url_content()` that uses `gl.nondet.web.render()` to fetch content.
- Uses `gl.eq_principle.strict_eq()` to ensure all nodes agree on the same content.
- **Read Method**:
- `show_content()` returns the stored web content.

## Key Components

1. **Web Integration**: The contract uses `gl.get_webpage()` to fetch content from web URLs.
2. **Deterministic Execution**: `gl.eq_principle_strict_eq()` ensures that all nodes in the network arrive at the same exact content.
1. **Web Integration**: The contract uses `gl.nondet.web.render()` to fetch content from web URLs.
2. **Deterministic Execution**: `gl.eq_principle.strict_eq()` ensures that all nodes in the network arrive at the same exact content.
3. **State Management**: The contract maintains a single string state variable that stores the web content.

## Deploying the Contract
Expand Down Expand Up @@ -101,7 +101,7 @@ You can monitor the contract's behavior through transaction logs, which will sho

## HTML Mode for Web Content

The `gl.get_webpage()` function supports different modes for retrieving web content. While `mode="text"` returns the plain text content, `mode="html"` allows you to retrieve the complete HTML `<body>` of the webpage.
The `gl.nondet.web.render()` function supports different modes for retrieving web content. While `mode="text"` returns the plain text content, `mode="html"` allows you to retrieve the complete HTML `<body>` of the webpage.

Here's an example of using HTML mode:

Expand All @@ -115,9 +115,9 @@ class FetchHTMLContent(gl.Contract):
@gl.public.write
def fetch_html_content(self) -> typing.Any:
def fetch_web_url_html() -> str:
return gl.get_webpage("https://example.com/", mode="html")
return gl.nondet.web.render("https://example.com/", mode="html")

self.html_content = gl.eq_principle_strict_eq(fetch_web_url_html)
self.html_content = gl.eq_principle.strict_eq(fetch_web_url_html)

@gl.public.view
def show_html_content(self) -> str:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class GitHubProfilesRepositories(gl.Contract):
github_profile_url = "https://github.com/"+github_handle

def fetch_github_profile_repositories() -> int:
profile_web_page = gl.get_webpage(github_profile_url, mode="text")
profile_web_page = gl.nondet.web.render(github_profile_url, mode="text")
# Regular expression to find the number between "Repositories" and "Projects"
pattern = r"Repositories\s+(\d+)\s+Projects"

Expand All @@ -33,7 +33,7 @@ class GitHubProfilesRepositories(gl.Contract):
else:
return 0

repositories = gl.eq_principle_strict_eq(fetch_github_profile_repositories)
repositories = gl.eq_principle.strict_eq(fetch_github_profile_repositories)

if repositories > 25:
self.github_profiles.append(github_handle)
Expand All @@ -55,9 +55,9 @@ class GitHubProfilesRepositories(gl.Contract):

## Key Components

1. **GitHub Integration**: Uses `gl.get_webpage()` to fetch profile content.
1. **GitHub Integration**: Uses `gl.nondet.web.render()` to fetch profile content.
2. **Pattern Matching**: Employs regular expressions to extract repository counts.
3. **Deterministic Execution**: Uses `gl.eq_principle_strict_eq()` to ensure network consensus.
3. **Deterministic Execution**: Uses `gl.eq_principle.strict_eq()` to ensure network consensus.
4. **Conditional Storage**: Only stores profiles meeting specific criteria.

## Deploying the Contract
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,17 @@ class GitHubProfilesSummaries(gl.Contract):
github_profile_url = "https://github.com/"+github_handle

def fetch_github_profile_summaries() -> str:
return gl.get_webpage(github_profile_url, mode="text")
return gl.nondet.web.render(github_profile_url, mode="text")

profile_content = gl.eq_principle_strict_eq(fetch_github_profile_summaries)
profile_content = gl.eq_principle.strict_eq(fetch_github_profile_summaries)

task = """Given the web page content of a github profile in HTML format, generate a comprehensive
summary of the profile mentioning the key meta attributes and the GitHub contribution most important metrics"""

criteria = """The summary provided should include different metrics and a summary of a GitHub profile"""

profile_summary = (
gl.eq_principle_prompt_non_comparative(
gl.eq_principle.prompt_non_comparative(
lambda: profile_content,
task=task,
criteria=criteria,
Expand All @@ -61,7 +61,7 @@ summary of the profile mentioning the key meta attributes and the GitHub contrib
## Key Components

1. **Data Storage**: Uses `TreeMap` for efficient key-value storage of profile summaries.
2. **Web Fetching**: Uses `gl.get_webpage()` with strict equivalence for deterministic content retrieval.
2. **Web Fetching**: Uses `gl.nondet.web.render()` with strict equivalence for deterministic content retrieval.
3. **AI Analysis**: Uses non-comparative equivalence for generating profile summaries.
4. **Duplicate Prevention**: Includes checks to prevent regenerating existing summaries.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class LlmHelloWorldNonComparative(gl.Contract):

@gl.public.write
def set_message(self) -> typing.Any:
self.message = gl.eq_principle_prompt_non_comparative(
self.message = gl.eq_principle.prompt_non_comparative(
lambda: "There is no context, I just want you to answer with truthy value in python (for example: 'yes', 'True', 1)",
task="Answer with truthy value in python (for example: 'yes', 'True', 1)",
criteria="Answer should be a truthy value in python"
Expand All @@ -33,7 +33,7 @@ class LlmHelloWorldNonComparative(gl.Contract):
- **Initialization**: The `LlmHelloWorldNonComparative` class initializes with an empty string in the `message` variable.
- **Write Method**:
- `set_message()` uses AI functionality to generate and store a message.
- Uses `gl.eq_principle_prompt_non_comparative()` with three parameters:
- Uses `gl.eq_principle.prompt_non_comparative()` with three parameters:
- A lambda function providing the prompt
- A task description
- Validation criteria for the response
Expand All @@ -43,7 +43,7 @@ class LlmHelloWorldNonComparative(gl.Contract):
## Key Components

1. **AI Integration**: The contract uses non-comparative equivalence principle to interact with an AI model.
2. **Deterministic Execution**: `gl.eq_principle_prompt_non_comparative()` ensures that all nodes in the network accept responses that meet the specified criteria.
2. **Deterministic Execution**: `gl.eq_principle.prompt_non_comparative()` ensures that all nodes in the network accept responses that meet the specified criteria.
3. **State Management**: The contract maintains a single string state variable that stores the AI response.

## Deploying the Contract
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ class LlmHelloWorld(gl.Contract):

def get_message() -> str:
task = "There is no context, I just want you to answer with a string equal to 'yes'"
result = gl.exec_prompt(task)
result = gl.nondet.exec_prompt(task)
print(result)
return result

self.message = gl.eq_principle_strict_eq(get_message)
self.message = gl.eq_principle.strict_eq(get_message)

@gl.public.view
def get_message(self) -> str:
Expand All @@ -37,14 +37,14 @@ class LlmHelloWorld(gl.Contract):
- **Write Method**:
- `set_message()` uses AI functionality to generate and store a message.
- It contains an inner function `get_message()` that prompts an AI model with a simple task.
- Uses `gl.eq_principle_strict_eq()` to ensure deterministic AI responses across the network.
- Uses `gl.eq_principle.strict_eq()` to ensure deterministic AI responses across the network.
- **Read Method**:
- `get_message()` returns the stored message.

## Key Components

1. **AI Integration**: The contract uses `gl.exec_prompt()` to interact with an AI model.
2. **Deterministic Execution**: `gl.eq_principle_strict_eq()` ensures that all nodes in the network arrive at the same exact result.
1. **AI Integration**: The contract uses `gl.nondet.exec_prompt()` to interact with an AI model.
2. **Deterministic Execution**: `gl.eq_principle.strict_eq()` ensures that all nodes in the network arrive at the same exact result.
3. **State Management**: The contract maintains a single string state variable that stores the AI response.

## Deploying the Contract
Expand Down
Loading