Skip to content

Latest commit

 

History

History

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 

README.md

PVQ Executor

The core execution engine for PVQ (PolkaVM Query) programs. This crate provides a secure, sandboxed environment for running guest programs compiled to RISC-V, with controlled access to runtime functionality through extensions.

Overview

The PVQ Executor serves as the bridge between compiled guest programs and the Substrate runtime. It manages PolkaVM instances, handles program lifecycle, and provides secure execution context for queries.

Features

  • 🔒 Secure Execution: Sandboxed PolkaVM environment with resource limits
  • High Performance: Optimized for fast query execution
  • 🛡️ Memory Safety: Controlled memory allocation and access
  • 🔌 Extension Integration: Seamless interaction with PVQ extensions
  • ⏱️ Timeout Protection: Configurable execution time limits
  • 📊 Resource Monitoring: Track memory usage and execution metrics

Architecture

┌─────────────────────────────────────────────────────────────┐
│                     PVQ Executor                            │
├─────────────────────────────────────────────────────────────┤
│  ┌─────────────────┐  ┌─────────────────┐  ┌──────────────┐ │
│  │   PvqExecutor   │  │ ExecutorContext │  │ PolkaVM      │ │
│  │                 │  │                 │  │ Instance     │ │
│  │ ├─ Lifecycle    │  │ ├─ Extensions   │  │              │ │
│  │ ├─ Resource     │  │ ├─ Runtime      │  │ ├─ Memory    │ │
│  │ │  Management   │  │ │  Access       │  │ ├─ Execution │ │
│  │ └─ Error        │  │ └─ Permissions  │  │ └─ Sandbox   │ │
│  │    Handling     │  │                 │  │              │ │
│  └─────────────────┘  └─────────────────┘  └──────────────┘ │
└─────────────────────────────────────────────────────────────┘

Core Components

PvqExecutor

The main executor that manages the complete lifecycle of PVQ program execution.

Responsibilities:

  • Program loading and validation
  • PolkaVM instance creation and management
  • Execution context setup
  • Resource limit enforcement
  • Error handling and recovery

PvqExecutorContext

Provides the execution context and environment for guest programs.

Responsibilities:

  • Extension registry management
  • Runtime state access
  • Permission control
  • Inter-component communication

Error Handling

Comprehensive error types covering all execution scenarios.

Error Categories:

  • Program loading errors
  • Execution timeout/resource exhaustion
  • Extension call failures
  • Memory access violations

Usage

Basic Execution

use pvq_executor::{PvqExecutor, PvqExecutorContext};
use pvq_extension::ExtensionsExecutor;

// Create executor context
let extensions = ExtensionsExecutor::new();
let context = PvqExecutorContext::new(extensions);

// Create and configure executor
let executor = PvqExecutor::new(context);

// Load and execute program
let program_blob = std::fs::read("program.polkavm")?;
let args = vec![1, 2, 3, 4]; // Serialized arguments

let result = executor.execute(&program_blob, &args)?;
println!("Execution result: {:?}", result);

Advanced Configuration

use pvq_executor::{PvqExecutor, PvqExecutorConfig, PvqExecutorContext};
use std::time::Duration;

// Configure execution parameters
let config = PvqExecutorConfig {
    max_memory: 32 * 1024 * 1024, // 32MB
    max_execution_time: Duration::from_secs(30),
    enable_debugging: false,
    stack_size: 1024 * 1024, // 1MB
};

// Create executor with custom config
let context = PvqExecutorContext::new(extensions);
let executor = PvqExecutor::with_config(context, config);

Error Handling

use pvq_executor::{PvqExecutor, PvqExecutorError};

match executor.execute(&program_blob, &args) {
    Ok(result) => {
        println!("Success: {:?}", result);
    }
    Err(PvqExecutorError::Timeout) => {
        eprintln!("Program execution timed out");
    }
    Err(PvqExecutorError::OutOfMemory) => {
        eprintln!("Program exceeded memory limits");
    }
    Err(PvqExecutorError::ExtensionError(e)) => {
        eprintln!("Extension call failed: {}", e);
    }
    Err(e) => {
        eprintln!("Execution failed: {}", e);
    }
}

Configuration

Execution Limits

Parameter Default Description
max_memory 16MB Maximum memory allocation
max_execution_time 10s Maximum execution duration
stack_size 512KB Program stack size
max_call_depth 1024 Maximum call stack depth

Security Settings

Setting Default Description
enable_debugging false Enable debug information
strict_memory true Strict memory access checking
extension_whitelist None Allowed extensions (None = all)

Performance Tuning

let config = PvqExecutorConfig {
    // Optimize for throughput
    max_memory: 64 * 1024 * 1024,
    precompile_programs: true,
    enable_jit: true,
    
    // Or optimize for safety
    max_execution_time: Duration::from_secs(5),
    strict_memory: true,
    enable_debugging: false,
};

Integration

With Substrate Runtime

use pvq_executor::{PvqExecutor, PvqExecutorContext};
use pvq_runtime_api::PvqApi;
use sp_api::ProvideRuntimeApi;

impl<Block: BlockT> PvqApi<Block> for Runtime {
    fn execute_query(&self, program: Vec<u8>, args: Vec<u8>) -> Vec<u8> {
        let extensions = self.create_extensions_executor();
        let context = PvqExecutorContext::new(extensions);
        let executor = PvqExecutor::new(context);
        
        executor.execute(&program, &args)
            .unwrap_or_else(|e| format!("Error: {}", e).into_bytes())
    }
}

With Extension System

use pvq_executor::PvqExecutorContext;
use pvq_extension::ExtensionsExecutor;
use pvq_extension_fungibles::ExtensionFungibles;

// Register extensions
let mut extensions = ExtensionsExecutor::new();
extensions.register::<ExtensionFungibles>();

// Create context with extensions
let context = PvqExecutorContext::new(extensions);

Development

Building

# Build the executor
cargo build -p pvq-executor

# Build with all features
cargo build -p pvq-executor --all-features

# Run tests
cargo test -p pvq-executor

Testing

# Run unit tests
cargo test -p pvq-executor

# Run integration tests  
cargo test -p pvq-executor --test integration

# Test with different configurations
cargo test -p pvq-executor --test config_tests

# Benchmark performance
cargo bench -p pvq-executor

Debugging

Enable debug logging:

use log::debug;

// In executor implementation
debug!("Executing program with {} bytes", program.len());
debug!("Memory usage: {} bytes", memory_usage);

Run with debug output:

RUST_LOG=pvq_executor=debug cargo test

Error Reference

PvqExecutorError Types

Error Type Description Recovery
InvalidProgram Malformed program blob Validate program before execution
Timeout Execution time limit exceeded Increase timeout or optimize program
OutOfMemory Memory limit exceeded Increase memory limit or optimize program
ExtensionError Extension call failed Check extension implementation
RuntimeError Runtime execution error Debug program logic

Common Issues

Program won't load:

# Validate program format
polkatool validate program.polkavm

# Check file size and format
file program.polkavm

Execution timeouts:

// Increase timeout for complex queries
let config = PvqExecutorConfig {
    max_execution_time: Duration::from_secs(60),
    ..Default::default()
};

Memory errors:

// Monitor memory usage
let config = PvqExecutorConfig {
    max_memory: 64 * 1024 * 1024, // Increase limit
    enable_debugging: true, // Enable memory tracking
    ..Default::default()
};

Performance

Optimization Tips

  1. Program Size: Keep programs small for faster loading
  2. Memory Access: Use sequential memory access patterns
  3. Extension Calls: Minimize expensive extension operations
  4. Data Structures: Use efficient serialization formats

Benchmarking

# Run performance benchmarks
cargo bench -p pvq-executor

# Profile memory usage
cargo run --example memory_profile --release

# Measure execution time
cargo run --example timing_analysis --release

Security Considerations

  • Programs execute in a sandboxed environment
  • Memory access is controlled and limited
  • Execution time is bounded to prevent DoS
  • Extension calls go through permission checks
  • No direct system call access from guest programs

Related Components


The PVQ Executor provides the secure foundation for all PVQ program execution.