What Are the Allowed Storage Types in GenLayer Intelligent Contracts?
GenLayer intelligent contracts support five deterministic storage types: TreeMap, DynArray, Array, u256/i256, and @allow_storage-decorated custom classes.
These types ensure that smart contract state can be reproduced identically across all validator nodes in the GenLayer network. The genlayer-project-boilerplate repository documents these constraints in CLAUDE.md and enforces them through the GenVM linter, which blocks nondeterministic Python data structures like standard dict and list.
Core Storage Types for GenLayer Contracts
GenLayer's storage system replaces Python's native collections with deterministic alternatives. Each type is optimized for specific access patterns while maintaining the reproducibility required for consensus.
TreeMap: Deterministic Ordered Mapping
TreeMap[Key, Value] provides O(log n) lookups with guaranteed insertion order. Unlike Python's dict, this structure produces identical iteration order on every node.
Use TreeMap for any key-value data that persists across blocks:
from genlayer import *
class Token(gl.Contract):
balances: TreeMap[Address, u256]
def __init__(self):
self.balances = TreeMap()
@gl.public.write
def transfer(self, to: Address, amount: u256):
sender = gl.message.sender_address
self.balances[sender] -= amount
self.balances[to] = self.balances.get(to, u256(0)) + amount
DynArray: Growable Deterministic Lists
DynArray[Element] supports dynamic sizing with predictable ordering. Use this when your collection needs to expand or contract during contract execution.
Typical applications include participant registries and pending transaction queues:
from genlayer import *
class Registry(gl.Contract):
participants: DynArray[Address]
def __init__(self):
self.participants = DynArray()
@gl.public.write
def join(self):
self.participants.append(gl.message.sender_address)
Array: Fixed-Size Collections
Array[Element] requires compile-time length knowledge. This constraint enables memory optimizations and guarantees stable indexing.
Best for leaderboards, round-robin slots, or other bounded collections:
from genlayer import *
class Leaderboard(gl.Contract):
top_scores: Array[u256] # Exactly 10 entries
def __init__(self):
self.top_scores = Array([u256(0)] * 10)
u256 and i256: Native Integer Types
These 256-bit integers replace Python's arbitrary-precision int for deterministic arithmetic. u256 handles unsigned values; i256 handles signed.
Always use these types for counters, balances, timestamps, and mathematical operations:
from genlayer import *
class Counter(gl.Contract):
value: u256
signed_delta: i256
def __init__(self):
self.value = u256(0)
self.signed_delta = i256(-5)
Creating Custom Storage Types with @allow_storage
The @allow_storage decorator extends the type system to user-defined classes. Decorated classes must contain only allowed storage primitives internally.
This pattern appears in contracts/football_bets.py from the boilerplate repository:
from genlayer import *
@allow_storage
class Bet:
amount: u256
choice: str
timestamp: u256
class FootballBets(gl.Contract):
bets: TreeMap[Address, TreeMap[str, Bet]]
points: TreeMap[Address, u256]
def __init__(self):
self.bets = TreeMap()
self.points = TreeMap()
@gl.public.write
def place_bet(self, match_id: str, amount: u256, choice: str):
user = gl.message.sender_address
user_bets = self.bets.get(user, TreeMap())
user_bets[match_id] = Bet(
amount=amount,
choice=choice,
timestamp=gl.vm.now()
)
self.bets[user] = user_bets
self.points[user] = self.points.get(user, u256(0)) + u256(1)
The nested TreeMap[str, Bet] structure enables efficient per-user, per-match bet tracking while maintaining full determinism.
Workarounds for Unsupported Patterns
Standard Python list cannot be stored directly in a TreeMap. The boilerplate demonstrates a JSON serialization pattern in contracts/PatternTest.py:
import json
from genlayer import *
class ListWrapper(gl.Contract):
data: TreeMap[str, str] # JSON-encoded lists
def __init__(self):
self.data = TreeMap()
@gl.public.write
def store_list(self, key: str, values: list[str]):
self.data[key] = json.dumps(values)
@gl.public.view
def retrieve_list(self, key: str) -> list[str]:
return json.loads(self.data.get(key, "[]"))
This approach trades some gas efficiency for flexibility when true nested collections are required.
Complete Storage Type Reference
| Type | Mutability | Use Case | Source Reference |
|---|---|---|---|
TreeMap[K,V] |
Mutable | Mappings with ordered iteration | CLAUDE.md line 72 |
DynArray[T] |
Mutable | Variable-length sequences | CLAUDE.md line 72 |
Array[T] |
Fixed-size | Compile-time bounded collections | CLAUDE.md line 72 |
u256 / i256 |
Value types | All numeric computation | CLAUDE.md line 72 |
@allow_storage classes |
Depends on fields | Domain-specific structs | contracts/football_bets.py |
Summary
- Five storage types are permitted in GenLayer intelligent contracts:
TreeMap,DynArray,Array,u256/i256, and@allow_storageclasses. - Native Python containers (
dict,list,set) are rejected by the GenVM linter to ensure deterministic execution. - Custom structs require the
@allow_storagedecorator and may only contain other allowed types. - Nested structures like
TreeMap[Address, TreeMap[str, Bet]]are fully supported as shown incontracts/football_bets.py. - Serialization workarounds enable storing complex data when direct container nesting is insufficient.
Frequently Asked Questions
What happens if I use a Python list in a GenLayer contract?
The GenVM linter will reject the contract during compilation. Standard Python list produces nondeterministic memory layouts that could cause consensus failures across validator nodes. Use DynArray for dynamic collections or Array for fixed-size needs.
Can I nest multiple storage types together?
Yes. The FootballBets example in contracts/football_bets.py demonstrates TreeMap[Address, TreeMap[str, Bet]] with a custom @allow_storage class at the deepest level. Arbitrary nesting of allowed types is permitted.
How do I store a variable-length list inside a TreeMap?
GenLayer does not support direct TreeMap[K, list[V]] storage. Serialize the list to JSON (or another deterministic format) and store as TreeMap[K, str] instead, as shown in contracts/PatternTest.py. Deserialize when reading.
Is there a size limit for DynArray or TreeMap?
The analysis does not specify explicit size limits. Practical limits are determined by gas costs for operations and the deterministic execution timeout in GenVM. For unbounded growth, consider pagination patterns or off-chain data with on-chain hashes.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →