synor/crates/synor-vm/src/lib.rs
Gulshan Yadav 771f4f83ed feat(compute): integrate synor-compute with VM and hosting layers
VM Integration:
- Add compute module with offloadable operations support
- Enable distributed execution for heavy VM operations
- Support batch signature verification, merkle proofs, hashing
- Add ComputeContext for managing compute cluster connections
- Feature-gated behind 'compute' flag

Hosting Integration:
- Add edge compute module for serverless functions
- Support edge functions (WASM, JS, Python runtimes)
- Enable server-side rendering and image optimization
- Add AI/ML inference at the edge
- Feature-gated behind 'compute' flag

Docker Deployment:
- Add docker-compose.compute.yml for compute layer
- Deploy orchestrator, CPU workers, WASM worker, spot market
- Include Redis for task queue and Prometheus for metrics
- Reserved ports: 17250-17290 for compute services
2026-01-11 14:05:45 +05:30

319 lines
9.6 KiB
Rust

//! WASM Virtual Machine for Synor smart contracts.
//!
//! Synor uses Rust-only smart contracts compiled to WebAssembly. This provides:
//! - Memory safety and type safety
//! - Predictable gas metering
//! - Sandboxed execution
//! - Rich standard library
//!
//! # Architecture
//!
//! ```text
//! ┌─────────────────────────────────────────────────────────────────┐
//! │ SMART CONTRACT VM │
//! ├─────────────────────────────────────────────────────────────────┤
//! │ │
//! │ ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐ │
//! │ │ WASM │ │ Host │ │ Contract │ │
//! │ │ Engine │ │ Functions │ │ Storage │ │
//! │ └──────┬───────┘ └──────┬───────┘ └──────────┬───────────┘ │
//! │ │ │ │ │
//! │ └─────────────────┼──────────────────────┘ │
//! │ │ │
//! │ ┌──────▼───────┐ │
//! │ │ Execution │ │
//! │ │ Context │ │
//! │ └──────────────┘ │
//! │ │
//! └─────────────────────────────────────────────────────────────────┘
//! ```
//!
//! # Contract Interface
//!
//! Contracts must export these functions:
//! - `init(params: &[u8]) -> Result<(), Error>` - Initialize contract
//! - `call(method: &str, params: &[u8]) -> Result<Vec<u8>, Error>` - Call method
#![allow(dead_code)]
pub mod compression;
pub mod compute;
pub mod context;
pub mod engine;
pub mod gas;
pub mod gas_estimator;
pub mod host;
pub mod scheduler;
pub mod speculation;
pub mod storage;
pub mod tiered;
pub use context::{CallContext, ExecutionContext};
pub use engine::{ContractModule, VmEngine, VmInstance};
pub use gas::{Gas, GasConfig, GasMeter};
pub use gas_estimator::{costs, GasEstimate, GasEstimator};
pub use host::HostFunctions;
pub use scheduler::{
AccessSet, ExecutionBatch, LockManager, ParallelExecutor, ParallelScheduler,
ScheduledResult, ScheduledTransaction, SchedulerConfig, SchedulerStats, TransactionBuilder,
};
pub use storage::{ContractStorage, MemoryStorage, StorageKey, StorageValue};
pub use tiered::{
CompilationTier, CompilerStatistics, TieredCompiler, TieredConfig, TieredModule,
};
pub use compression::{
BytecodeCompressor, CompressedBytecode, CompressedContractStore, CompressionConfig,
CompressionLevel, CompressionStats, DeltaPatch,
};
pub use speculation::{
CachedState, ContractCache, GlobalCacheStats, HotStateCache, PendingExecution,
SpeculativeConfig, SpeculativeContext, SpeculativeExecutor, SpeculativeResult,
SpeculativeStats, StateSnapshot, StateVersion,
};
use synor_types::{Address, Hash256};
/// Maximum contract code size (1 MB).
pub const MAX_CONTRACT_SIZE: usize = 1024 * 1024;
/// Maximum memory pages (64 KB each, max 16 MB).
pub const MAX_MEMORY_PAGES: u32 = 256;
/// Maximum call depth.
pub const MAX_CALL_DEPTH: u32 = 64;
/// Maximum execution time (milliseconds).
pub const MAX_EXECUTION_TIME_MS: u64 = 30_000;
/// Contract identifier.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ContractId(pub Hash256);
impl ContractId {
/// Creates a new contract ID.
pub fn new(hash: Hash256) -> Self {
ContractId(hash)
}
/// Creates from bytes.
pub fn from_bytes(bytes: [u8; 32]) -> Self {
ContractId(Hash256::from_bytes(bytes))
}
/// Returns as bytes.
pub fn as_bytes(&self) -> &[u8; 32] {
self.0.as_bytes()
}
}
impl std::fmt::Display for ContractId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", hex::encode(&self.0.as_bytes()[..8]))
}
}
/// Contract execution result.
#[derive(Clone, Debug)]
pub struct ExecutionResult {
/// Return data.
pub return_data: Vec<u8>,
/// Gas used.
pub gas_used: u64,
/// Logs emitted.
pub logs: Vec<ContractLog>,
/// Storage changes.
pub storage_changes: Vec<StorageChange>,
/// Internal calls made.
pub internal_calls: Vec<InternalCall>,
}
impl ExecutionResult {
/// Creates a successful empty result.
pub fn success() -> Self {
ExecutionResult {
return_data: Vec::new(),
gas_used: 0,
logs: Vec::new(),
storage_changes: Vec::new(),
internal_calls: Vec::new(),
}
}
/// Creates a result with return data.
pub fn with_data(data: Vec<u8>) -> Self {
ExecutionResult {
return_data: data,
gas_used: 0,
logs: Vec::new(),
storage_changes: Vec::new(),
internal_calls: Vec::new(),
}
}
}
/// Log emitted by a contract.
#[derive(Clone, Debug)]
pub struct ContractLog {
/// Contract that emitted the log.
pub contract: ContractId,
/// Log topics (indexed).
pub topics: Vec<Hash256>,
/// Log data.
pub data: Vec<u8>,
}
/// Storage change made by a contract.
#[derive(Clone, Debug)]
pub struct StorageChange {
/// Contract storage.
pub contract: ContractId,
/// Storage key.
pub key: StorageKey,
/// Old value (None if new).
pub old_value: Option<StorageValue>,
/// New value (None if deleted).
pub new_value: Option<StorageValue>,
}
/// Internal contract call.
#[derive(Clone, Debug)]
pub struct InternalCall {
/// Caller contract.
pub from: ContractId,
/// Callee contract.
pub to: ContractId,
/// Method called.
pub method: String,
/// Call value.
pub value: u64,
/// Gas limit.
pub gas_limit: u64,
/// Input data.
pub input: Vec<u8>,
/// Success status.
pub success: bool,
/// Return data.
pub return_data: Vec<u8>,
}
/// Contract deployment parameters.
#[derive(Clone, Debug)]
pub struct DeployParams {
/// Contract bytecode (WASM).
pub code: Vec<u8>,
/// Constructor arguments.
pub args: Vec<u8>,
/// Initial value to send.
pub value: u64,
/// Gas limit.
pub gas_limit: u64,
/// Deployer address.
pub deployer: Address,
/// Salt for CREATE2-style addresses.
pub salt: Option<Hash256>,
}
/// Contract call parameters.
#[derive(Clone, Debug)]
pub struct CallParams {
/// Target contract.
pub contract: ContractId,
/// Method to call.
pub method: String,
/// Call arguments.
pub args: Vec<u8>,
/// Value to send.
pub value: u64,
/// Gas limit.
pub gas_limit: u64,
/// Caller address.
pub caller: Address,
}
/// VM errors.
#[derive(Debug, Clone, thiserror::Error)]
pub enum VmError {
/// Contract not found.
#[error("Contract not found: {0}")]
ContractNotFound(ContractId),
/// Invalid bytecode.
#[error("Invalid bytecode: {0}")]
InvalidBytecode(String),
/// Bytecode too large.
#[error("Bytecode too large: {size} > {max}")]
BytecodeTooLarge { size: usize, max: usize },
/// Out of gas.
#[error("Out of gas: used {used}, limit {limit}")]
OutOfGas { used: u64, limit: u64 },
/// Execution error.
#[error("Execution error: {0}")]
ExecutionError(String),
/// Memory access violation.
#[error("Memory access violation: {0}")]
MemoryViolation(String),
/// Stack overflow.
#[error("Stack overflow")]
StackOverflow,
/// Call depth exceeded.
#[error("Call depth exceeded: {0} > {}", MAX_CALL_DEPTH)]
CallDepthExceeded(u32),
/// Execution timeout.
#[error("Execution timeout")]
Timeout,
/// Invalid method.
#[error("Invalid method: {0}")]
InvalidMethod(String),
/// Serialization error.
#[error("Serialization error: {0}")]
SerializationError(String),
/// Storage error.
#[error("Storage error: {0}")]
StorageError(String),
/// Host function error.
#[error("Host function error: {0}")]
HostError(String),
/// Contract panicked.
#[error("Contract panicked: {0}")]
Panic(String),
/// Reverted by contract.
#[error("Reverted: {0}")]
Revert(String),
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_contract_id() {
let hash = Hash256::from_bytes([0x42; 32]);
let id = ContractId::new(hash);
assert_eq!(id.as_bytes(), &[0x42; 32]);
assert!(!id.to_string().is_empty());
}
#[test]
fn test_execution_result() {
let result = ExecutionResult::success();
assert!(result.return_data.is_empty());
assert_eq!(result.gas_used, 0);
let result = ExecutionResult::with_data(vec![1, 2, 3]);
assert_eq!(result.return_data, vec![1, 2, 3]);
}
}