Skip to main content

A Python linter for GenLayer GenVM intelligent contracts

Project description

GenVM Linter

A Python linter specifically designed for GenLayer GenVM intelligent contracts. This linter validates GenLayer intelligent contracts according to GenVM's type system and coding conventions.

Features

โœจ Comprehensive Validation

  • Magic comment validation (# { "Depends": "py-genlayer:test" })
  • GenLayer import checking (from genlayer import *)
  • Contract class structure validation
  • Method decorator validation (@gl.public.view, @gl.public.write)
  • Type system enforcement (sized integers, collections, dataclasses)

๐Ÿ”ง Type System Rules

  • Enforces use of sized integers (u64, u256, etc.) in storage fields
  • Prevents use of int return types (should use int instead of u256)
  • Validates proper collection types (DynArray vs list, TreeMap vs dict)
  • Checks @allow_storage decorator usage on dataclasses

๐ŸŽฏ Smart Error Detection

  • Detects missing or incorrect decorators
  • Identifies state modification in view methods
  • Validates constructor decoration rules
  • Comprehensive error messages with suggestions

Installation

From Source

git clone https://github.com/genlayerlabs/genvm-linter.git
cd genvm-linter
pip install -e .

Using pip (when published)

pip install genvm-linter

Usage

Command Line

# Lint a single file
genvm-lint contract.py

# Lint all Python files in a directory
genvm-lint contracts/

# Show only errors
genvm-lint --severity error contract.py

# Output as JSON
genvm-lint --format json contract.py

# Show statistics
genvm-lint --stats contracts/

# Run specific rules only
genvm-lint --rule genvm-types --rule genvm-decorators contract.py

# Exclude specific rules
genvm-lint --exclude-rule genvm-magic-comment contract.py

Python API

from genvm_linter import GenVMLinter

# Create linter instance
linter = GenVMLinter()

# Lint a file
results = linter.lint_file("path/to/contract.py")

# Lint source code directly
source_code = '''
# { "Depends": "py-genlayer:test" }
from genlayer import *

class MyContract(gl.Contract):
    balance: u256
    
    def __init__(self, initial_balance: int):
        self.balance = initial_balance
    
    @gl.public.view
    def get_balance(self) -> int:
        return self.balance
'''

results = linter.lint_source(source_code)

# Process results
for result in results:
    print(f"{result.severity.value}: {result.message}")
    if result.suggestion:
        print(f"๐Ÿ’ก {result.suggestion}")

Validation Rules

Required Structure Rules

Rule ID Description
genvm-magic-comment First line must contain # { "Depends": "py-genlayer:test" }
genvm-import Must include from genlayer import *
genvm-contract-class Exactly one class extending gl.Contract

Decorator Rules

Rule ID Description
genvm-decorators Proper usage of @gl.public.view and @gl.public.write

Decorator Requirements:

  • __init__ methods must NOT have public decorators
  • Public methods must have exactly one @gl.public.* decorator
  • Private methods (starting with _) should not have public decorators
  • Use @gl.public.view for read-only methods
  • Use @gl.public.write for state-modifying methods

Type System Rules

Rule ID Description
genvm-types Validates GenVM type system usage

Type System Requirements:

Storage Fields

  • โœ… Use sized integers: u8, u16, u32, u64, u128, u256, i8, i16, etc.
  • โŒ Don't use plain int in storage annotations
  • โœ… Use DynArray[T] instead of list[T]
  • โœ… Use TreeMap[K, V] instead of dict[K, V]

Method Return Types

  • โœ… Use int for return type annotations
  • โŒ Don't use sized integers (u256, etc.) in return types

Dataclasses

  • Use @allow_storage decorator for dataclasses used in storage
  • Consider sized integers for dataclass fields

Example: Valid Contract

# { "Depends": "py-genlayer:test" }

from genlayer import *
from dataclasses import dataclass

@allow_storage
@dataclass
class UserData:
    name: str
    balance: u256
    is_active: bool

class TokenContract(gl.Contract):
    owner: Address
    users: TreeMap[Address, UserData]
    total_supply: u256

    def __init__(self, initial_supply: int):
        self.owner = gl.message.sender_address
        self.total_supply = initial_supply

    @gl.public.view
    def get_balance(self, user: str) -> int:
        address = Address(user)
        user_data = self.users.get(address)
        return user_data.balance if user_data else 0

    @gl.public.write
    def transfer(self, to: str, amount: int):
        # Transfer logic here
        to_address = Address(to)
        # ... implementation

Example: Common Issues

# โŒ Missing magic comment
from genlayer import *  # Should have magic comment above

class BadContract(gl.Contract):
    balance: int  # โŒ Should be u256
    users: dict[str, int]  # โŒ Should be TreeMap[Address, u256]
    items: list[str]  # โŒ Should be DynArray[str]

    def __init__(self, initial_balance: int):
        self.balance = initial_balance

    # โŒ Missing decorator
    def get_balance(self) -> u256:  # โŒ Should return int
        return self.balance

    @gl.public.view  # โŒ Wrong decorator for state modification
    def set_balance(self, amount: int):
        self.balance = amount

Development

Setup Development Environment

git clone https://github.com/genlayerlabs/genvm-linter.git
cd genvm-linter

# Install in development mode
pip install -e ".[dev]"

# Run tests
pytest

# Run linter on itself
genvm-lint src/

# Format code
black src/ tests/
isort src/ tests/

# Type checking
mypy src/

Project Structure

genvm-linter/
โ”œโ”€โ”€ src/genvm_linter/
โ”‚   โ”œโ”€โ”€ __init__.py          # Main package
โ”‚   โ”œโ”€โ”€ linter.py            # Core linter logic
โ”‚   โ”œโ”€โ”€ cli.py               # Command-line interface
โ”‚   โ””โ”€โ”€ rules/               # Validation rules
โ”‚       โ”œโ”€โ”€ __init__.py
โ”‚       โ”œโ”€โ”€ base.py          # Base rule classes
โ”‚       โ”œโ”€โ”€ contract.py      # Contract structure rules
โ”‚       โ”œโ”€โ”€ decorators.py    # Decorator validation
โ”‚       โ”œโ”€โ”€ types.py         # Type system rules
โ”‚       โ”œโ”€โ”€ genvm_patterns.py # GenVM API patterns
โ”‚       โ””โ”€โ”€ python_types.py  # MyPy integration
โ”œโ”€โ”€ tests/
โ”‚   โ”œโ”€โ”€ unit/                # Unit tests
โ”‚   โ”œโ”€โ”€ integration/         # Integration tests
โ”‚   โ”œโ”€โ”€ fixtures/            # Test contract files
โ”‚   โ””โ”€โ”€ examples/            # Example contracts
โ”œโ”€โ”€ ARCHITECTURE.md          # System architecture
โ”œโ”€โ”€ CONTRIBUTING.md          # Contribution guidelines
โ”œโ”€โ”€ CHANGELOG.md             # Version history
โ”œโ”€โ”€ pyproject.toml           # Package configuration
โ””โ”€โ”€ README.md                # This file

Documentation

VS Code Extension

The VS Code extension for this linter is maintained in a separate repository: GenLayer VS Code Extension

Contributing

Please see CONTRIBUTING.md for detailed guidelines on how to contribute to this project.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Related Projects

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

genvm_linter-0.1.0.tar.gz (46.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

genvm_linter-0.1.0-py3-none-any.whl (32.1 kB view details)

Uploaded Python 3

File details

Details for the file genvm_linter-0.1.0.tar.gz.

File metadata

  • Download URL: genvm_linter-0.1.0.tar.gz
  • Upload date:
  • Size: 46.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for genvm_linter-0.1.0.tar.gz
Algorithm Hash digest
SHA256 05c7676f32ab53499bff0c29e092d5589062f6dd368b86163fc22f71991347ca
MD5 0e7216edefb3cde4511d7eb853db0d5d
BLAKE2b-256 9bc17937326f0c4561e400f18877773c21690b4727144d32f3ce21be8bfed3c9

See more details on using hashes here.

File details

Details for the file genvm_linter-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: genvm_linter-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 32.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.7

File hashes

Hashes for genvm_linter-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 92c6315339a48b148799cfb8c07862924f3b5c1c4d7e7194e67dabe3fb2ba0c6
MD5 f21c706c2a99543eb8b998329fed32b8
BLAKE2b-256 8fa91dfec69f18dcba886cc1d4c705eb6360072a39d3b3b1baa7e0f1e8878075

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page