Skip to content
Open
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
149 changes: 149 additions & 0 deletions pages/_temp/security-and-best-practices/best-practices.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# Best Practices for Intelligent Contracts

> Best practices for writing efficient, reliable, and maintainable Intelligent Contracts on GenLayer.

---

## 1. Structure your contract clearly

Follow a consistent layout: storage declarations at the top, `__init__` next, then read-only (view) methods, then write methods. Non-deterministic blocks should be small, self-contained functions immediately adjacent to the call that uses them.

**Recommended contract layout:**

```python
from genlayer import *

class MyContract(gl.Contract):
# 1. Storage
owner: Address
data: TreeMap[str, str]

# 2. Init
def __init__(self, owner: Address):
self.owner = owner
self.data = TreeMap()

# 3. View methods
@gl.public.view
def get_value(self, key: str) -> str:
return self.data.get(key, "")

# 4. Write methods
@gl.public.write
def set_value(self, key: str, value: str) -> None:
assert gl.message.sender == self.owner, "Not authorized"

def _fetch_and_validate() -> bool:
page = gl.get_webpage(value, mode="text")
return gl.eq_principle_prompt_comparative(
lambda: "Is this a valid non-empty URL response? " + page[:200],
"yes or no"
)

if gl.eq_principle_strict_eq(_fetch_and_validate):
self.data[key] = value
Comment on lines +36 to +44
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

What are the exact equivalence principle functions available in GenLayer's Python API? Specifically, verify if gl.eq_principle_prompt_comparative and gl.eq_principle_strict_eq exist.

💡 Result:

The exact equivalence principle functions available in GenLayer's Python API under gl.eq_principle are: - strict_eq: Checks for strict equality between leader and validator results. Most performant but strict. - prompt_comparative: Uses NLP/LLM to compare leader and validator results for equivalence based on a provided principle. - prompt_non_comparative: Non-comparative principle for subjective tasks, where validators check if the leader's output meets task criteria. gl.eq_principle_prompt_comparative and gl.eq_principle_strict_eq do not exist as named functions. The functions are accessed as gl.eq_principle.strict_eq and gl.eq_principle.prompt_comparative. There are similar functions in genlayer.std.eq_principles (eq_principle_prompt_comparative, eq_principle_strict_eq), but the primary API uses the gl.eq_principle namespace.

Citations:


🏁 Script executed:

#!/bin/bash
# Search for equivalence principle API definitions and usage examples

echo "=== Searching for equivalence principle API patterns ==="
rg -n -C5 "eq_principle" --type=py --type=md

echo -e "\n=== Searching for genlayer module imports ==="
rg -n "from genlayer import|import genlayer" --type=py

Repository: genlayerlabs/genlayer-docs

Length of output: 7345


Update deprecated equivalence principle API calls.

Lines 38 and 43 use deprecated GenLayer API functions that must be updated:

  • gl.eq_principle_prompt_comparativegl.eq_principle.prompt_comparative (line 38)
  • gl.eq_principle_strict_eqgl.eq_principle.strict_eq (line 43)

Additionally, line 37 uses the deprecated gl.get_webpage function, which should be replaced with gl.nondet.web.get or gl.nondet.web.render.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pages/_temp/security-and-best-practices/best-practices.md` around lines 36 -
44, Update deprecated GenLayer usages: replace gl.get_webpage(...) with the
nondeterministic web API (use gl.nondet.web.get or gl.nondet.web.render
depending on whether you need raw text or rendered HTML) for the page retrieval,
change gl.eq_principle_prompt_comparative(...) to
gl.eq_principle.prompt_comparative(...), and change
gl.eq_principle_strict_eq(...) to gl.eq_principle.strict_eq(...); keep the same
inputs and lambda wrapper for the prompt but call the new names (e.g., use
gl.nondet.web.get(value) and pass its truncated result into
gl.eq_principle.prompt_comparative and then into gl.eq_principle.strict_eq to
assign self.data[key]).

```

---

## 2. Keep non-deterministic blocks minimal

Non-deterministic blocks run on every validator. The more they do, the more LLM calls and web fetches you pay for — and the harder it is to reach consensus. Extract only the judgment you need.

**Avoid — doing too much in one block:**

```python
def _block():
page = gl.get_webpage(url)
summary = gl.exec_prompt("Summarize: " + page)
score = gl.exec_prompt("Rate 1-10: " + summary)
tags = gl.exec_prompt("Extract tags: " + page)
return summary, score, tags
```

**Prefer — one focused judgment per block:**

```python
def _block():
page = gl.get_webpage(url)
return gl.exec_prompt(
"Is this page about AI? Answer yes or no.\n" + page
)
```

---

## 3. Choose the right equivalence principle

Picking the wrong principle is the most common source of `UNDETERMINED` transactions. Use the table below to guide your choice:

| Situation | Use | Example |
|---|---|---|
| All validators must match exactly | `strict_eq` | Fetching a price, parsing a number |
| LLM outputs may differ but mean the same | `prompt_comparative` | Sentiment check, yes/no decisions |
| You define what "equal enough" means | `prompt_non_comparative` | Grading, scoring, classification |

> **Warning:** Using `strict_eq` on a free-text LLM response almost always results in `UNDETERMINED`. Always constrain LLM outputs to structured answers (yes/no, a number, a category) when using `strict_eq`.

---

## 4. Validate external data before storing

Never write raw web data directly into storage. Validate structure and length before persisting.

```python
def _validate_price(url: str) -> float:
raw = gl.get_webpage(url, mode="text")
price_str = gl.exec_prompt(
f"Extract the numeric price from this text. "
f"Return only the number, no currency symbol.\n{raw[:500]}"
)
price = float(price_str.strip())
assert 0 < price < 1_000_000, "Price out of range"
return price
```

---

## 5. Minimize storage reads in write methods

Storage reads inside write methods still incur cost. Cache values in local variables when you need them multiple times within a single method call.

```python
# Instead of reading self.counter twice:
count = self.counter
count += 1
self.counter = count
self._emit_count_event(count) # reuse local var
```

---

## 6. Use access control on every write method

Any method decorated with `@gl.public.write` is callable by anyone on-chain. Explicitly check `gl.message.sender` at the top of every method that should be restricted.

```python
@gl.public.write
def admin_reset(self) -> None:
assert gl.message.sender == self.owner, "Only owner"
self.data = TreeMap()
```

---

## 7. Test with multiple validators

A contract that passes on 1 validator may fail with 5 due to LLM variance. Always run integration tests with at least 3–5 validators before deploying to testnet.

```python
sim_createRandomValidators(5, "openai", ["gpt-4"])
```

---

## See also

- [Equivalence Principle](../core-concepts/equivalence-principle.md)
- [Security Checklist](./security-checklist.md)
- [Debugging Intelligent Contracts](./debugging.md)
127 changes: 127 additions & 0 deletions pages/_temp/security-and-best-practices/genlayer-vs-solidity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# GenLayer vs Solidity: Migration Guide

> A quick-reference for developers coming from Ethereum/Solidity. This page maps familiar Solidity concepts to their GenLayer equivalents and highlights the key mental model shifts.

---

## Concept mapping

| Concept | Solidity | GenLayer (Python) |
|---|---|---|
| Language | Solidity (`.sol`) | Python (`.py`) via GenVM |
| Contract declaration | `contract Foo { }` | `class Foo(gl.Contract): ...` |
| State variables | Top-level typed declarations | Class-level annotated attributes, e.g. `count: u256` |
| Constructor | `constructor(...)` | `def __init__(self, ...)` |
| View function | `view` modifier | `@gl.public.view` |
| Write function | (default, no modifier needed) | `@gl.public.write` |
| Mapping | `mapping(K => V)` | `TreeMap[K, V]` |
| Dynamic array | `T[]` | `DynArray[T]` |
| Caller address | `msg.sender` | `gl.message.sender` |
| Value sent | `msg.value` | `gl.message.value` |
| Revert / error | `revert(...)` / `require(...)` | `assert ...` / `raise Exception(...)` |
| Cross-contract call | `IFoo(addr).bar()` | `gl.contract_at(addr, Foo).bar()` |
| External data (oracle) | Chainlink / oracle services | `gl.get_webpage(url)` natively |
| AI / LLM | Not possible | `gl.exec_prompt(prompt)` natively |
| Consensus model | Deterministic EVM execution | Optimistic Democracy + equivalence principles |
| Transaction outcomes | Success or revert | Success, revert, or `UNDETERMINED` |

---

## Key mental model shifts

### 1. Determinism is opt-in for AI and web operations

In Solidity, every operation must be deterministic — the EVM enforces this at the protocol level. In GenLayer, deterministic and non-deterministic code coexist in the same contract, but they must be **explicitly separated** into non-deterministic blocks.

Business logic outside those blocks is still fully deterministic. Think of non-deterministic blocks as sandboxed AI calls whose result is then fed back into deterministic logic.

```python
@gl.public.write
def update_status(self, url: str) -> None:
# This outer code is deterministic
assert gl.message.sender == self.owner, "Not authorized"

# Non-deterministic block — isolated AI/web logic
def _check():
page = gl.get_webpage(url, mode="text")
return gl.exec_prompt("Is this page live? Answer yes or no.\n" + page[:300])

# Back to deterministic — store the consensus result
self.is_live = gl.eq_principle_strict_eq(_check) == "yes"
```

---

### 2. Transactions may be UNDETERMINED, not just reverted

Solidity transactions have two outcomes: success or revert. GenLayer adds a third: **`UNDETERMINED`**, meaning validators ran the contract but could not reach consensus on the output.

This happens when:
- An LLM produces sufficiently different outputs across validators.
- `strict_eq` is used on free-text LLM output.
- Web fetches return different content on different validators (e.g. live prices, timestamps).

Design your equivalence principle and prompt structure to minimize `UNDETERMINED` results. Constraining LLM output to yes/no, a specific category, or a number is the most reliable approach.

---

### 3. No native event system — use storage for history

Solidity has `event` declarations and `emit` for off-chain indexing. GenLayer does not have a native event system yet. If you need queryable history, store it explicitly.

```python
# Solidity pattern (not available in GenLayer):
# emit Transfer(from, to, amount);

# GenLayer equivalent — store a log in a DynArray:
class TokenContract(gl.Contract):
transfer_log: DynArray[str]

@gl.public.write
def transfer(self, to: Address, amount: u256) -> None:
# ... transfer logic ...
entry = f"{gl.message.sender}->{to}:{amount}"
self.transfer_log.append(entry)
```

---

### 4. No built-in oracles — web access is native

In Solidity, fetching external data requires a trusted oracle service (Chainlink, etc.), which adds cost, latency, and a trust assumption. In GenLayer, `gl.get_webpage(url)` is a first-class protocol primitive — no third-party oracle needed.

Multi-validator consensus on the fetched data replaces the oracle's trust model.

---

### 5. Storage types are different

GenLayer's storage types are Python-native but have blockchain-specific semantics. The key types:

| Solidity | GenLayer | Notes |
|---|---|---|
| `mapping(K => V)` | `TreeMap[K, V]` | Ordered; supports iteration |
| `T[]` (dynamic) | `DynArray[T]` | Dynamic array |
| `T[N]` (fixed) | Python list (fixed size) | Initialized in `__init__` |
| `struct Foo` | `@dataclass class Foo` | Use `gl.Dataclass` |
| `address` | `Address` | GenLayer address type |
| `uint256` | `u256` | And `u8`, `u32`, `u64`, `i256`, etc. |

---

## Quick start for Solidity developers

1. Install the GenLayer CLI: `npm install -g genlayer`
2. Scaffold a project: `genlayer init my-project`
3. Replace your `.sol` file with a `.py` file following the `class MyContract(gl.Contract)` pattern
4. Run the GenLayer Studio locally to test with multiple validators
5. Deploy to testnet: `genlayer deploy --contract contracts/my_contract.py`

---

## See also

- [Introduction to Intelligent Contracts](../intelligent-contracts/introduction.md)
- [Types Reference](../intelligent-contracts/types.md)
- [Best Practices](./best-practices.md)
- [Your First Intelligent Contract](../intelligent-contracts/first-intelligent-contract.md)
Comment on lines +122 to +127
Copy link
Copy Markdown
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:

#!/bin/bash
# Search for the actual locations of referenced documentation files

echo "=== Searching for intelligent contracts documentation ==="
fd -t f "introduction|types|first-intelligent-contract" --extension md --extension mdx --exec echo "Found: {}"

echo -e "\n=== Checking directory structure ==="
fd -t d "intelligent" --exec echo "Directory: {}"

Repository: genlayerlabs/genlayer-docs

Length of output: 458


🏁 Script executed:

#!/bin/bash
# Search for types-related documentation in intelligent-contracts directory
echo "=== Checking intelligent-contracts directory contents ==="
ls -la pages/developers/intelligent-contracts/ 2>/dev/null | grep -E '\.(md|mdx)$'

echo -e "\n=== Broader search for 'types' files ==="
fd "types" pages/developers/intelligent-contracts/ -t f

echo -e "\n=== Verify Best Practices file referenced in links ==="
fd "best-practices" -t f --extension md --extension mdx

echo -e "\n=== Verify full path structure ==="
tree -L 3 pages/developers/ 2>/dev/null || find pages/developers -maxdepth 3 -type d

Repository: genlayerlabs/genlayer-docs

Length of output: 3403


Fix documentation link paths and extensions.

The "See also" links have two critical issues:

  1. Incorrect directory path: The paths use ../intelligent-contracts/ which resolves to pages/_temp/intelligent-contracts/ (nonexistent). The correct path is ../../developers/intelligent-contracts/.

  2. Wrong file extensions and missing files:

    • Links reference .md files, but actual files use .mdx extension
    • types.md does not exist; there's a types/ directory instead with multiple type reference files (address.mdx, collections.mdx, dataclasses.mdx, primitive.mdx)

Update lines 124-127 to:

  • ../../developers/intelligent-contracts/introduction.mdx
  • ../../developers/intelligent-contracts/types/ (or remove if a single page reference is needed)
  • ../../developers/intelligent-contracts/first-intelligent-contract.mdx

Line 126 (./best-practices.md) is already correct.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pages/_temp/security-and-best-practices/genlayer-vs-solidity.md` around lines
122 - 127, Update the "See also" link list under the "See also" heading: change
"../intelligent-contracts/introduction.md" to
"../../developers/intelligent-contracts/introduction.mdx", change
"../intelligent-contracts/types.md" to point to the types directory as
"../../developers/intelligent-contracts/types/" (or remove if you prefer a
single page), and change
"../intelligent-contracts/first-intelligent-contract.md" to
"../../developers/intelligent-contracts/first-intelligent-contract.mdx"; leave
"./best-practices.md" as-is.

Loading