Entorno de Ejecución de Contratos
El entorno de ejecución de contratos de Savitri ejecuta contratos inteligentes en un entorno aislado (sandbox) con medición de gas, aislamiento de almacenamiento y emisión de eventos.
Flujo de Ejecución
Contract Call TX arrives
│
▼
BaseContract validation
│ check paused, owner, reserved slots
▼
Gas Meter initialization
│ gas_limit from TX fee
▼
ContractStorage setup
│ load contract state, init cache
▼
Function dispatch
│ match function_selector → handler
▼
Execution (with gas tracking)
│ SLOAD, SSTORE, events, calls
▼
Result
├── Success → commit storage, emit events
└── Failure → revert all changes
BaseContract
Todos los contratos extienden BaseContract. Las ranuras 0-99 están reservadas:
| Ranura | Campo | Tamaño | Descripción |
|---|---|---|---|
| 0 | owner | 32 bytes | Dirección del propietario del contrato |
| 1 | version | u64 | Versión del contrato |
| 2 | governance_hook | bool | Integración de gobernanza habilitada |
| 3 | fee_hook | bool | Lógica de tarifa personalizada habilitada |
| 4 | paused | bool | Estado de pausa del contrato |
| 5-99 | Reservado | - | Uso futuro |
Funciones de BaseContract
| Función | Acceso | Descripción |
|---|---|---|
owner() | Público | Obtener el propietario del contrato |
transfer_ownership(new_owner) | Solo propietario | Transferir propiedad |
version() | Público | Obtener versión del contrato |
upgrade(new_version) | Solo propietario | Actualizar contrato |
pause() | Solo propietario | Pausar todas las operaciones |
unpause() | Solo propietario | Reanudar operaciones |
Medición de Gas
Costos de Gas
| Operación | Gas | Descripción |
|---|---|---|
SLOAD | 100 | Lectura de almacenamiento |
SSTORE (nuevo) | 20,000 | Escritura en almacenamiento (ranura vacía) |
SSTORE (actualizar) | 5,000 | Escritura en almacenamiento (ranura existente) |
CALL | 2,300 | Llamada entre contratos |
CREATE | 32,000 | Despliegue de contrato |
TRANSFER | 300 | Transferencia de tokens |
LOG | 375 | Emisión de evento (base) |
LOG_TOPIC | 375 | Por tema adicional |
LOG_DATA | 8 | Por byte de datos de evento |
CALLDATA | 16 | Por byte de datos de llamada |
Contabilidad por Lotes
El medidor de gas usa contabilidad por lotes (100 operaciones por lote) para reducir la sobrecarga. El gas se confirma en lotes en lugar de por operación.
Límite de Gas
El límite de gas se deriva de la tarifa de transacción:
gas_limit = tx.fee / gas_price
Si el gas se agota durante la ejecución, toda la transacción se revierte.
Almacenamiento de Contratos
Modelo Basado en Ranuras
Cada contrato tiene un almacén independiente de clave-valor donde las claves son números de ranura u64 y los valores son arreglos de 32 bytes.
Derivación de Ranuras
Para mapeos, las ranuras se derivan mediante Keccak256 para prevenir colisiones:
// Simple value
slot = FIXED_SLOT_NUMBER
// Mapping (address → value)
slot = keccak256(address || base_slot)[0..8] as u64
// Nested mapping (address → address → value)
inner = keccak256(outer_key || base_slot)
slot = keccak256(inner_key || inner)[0..8] as u64
Árbol de Merkle
El almacenamiento de contratos mantiene un árbol de Merkle para la generación de pruebas de estado.
Sistema de Eventos
Los contratos emiten eventos para consumidores externos:
pub struct CustomEvent {
pub event_type: String, // e.g., "Transfer", "Approval"
pub topics: Vec<Vec<u8>>, // indexed fields
pub data: Vec<u8>, // non-indexed data
}
Eventos estándar (desde BaseContract):
OwnershipTransferred(old_owner, new_owner)ContractUpgraded(old_version, new_version)Paused(by)Unpaused(by)
Despliegue de Contratos
1. Create DeployTransaction (to = None, data = bytecode)
2. Assign contract address (derived from deployer + nonce)
3. Initialize BaseContract (set owner, version)
4. Run contract constructor (initialize function)
5. Store ContractInfo in CF_CONTRACTS
6. Emit ContractDeployed event
Llamadas a Contratos
1. Parse function_selector from TX data
2. Load contract from CF_CONTRACTS
3. Check BaseContract state (not paused, etc.)
4. Initialize GasMeter with gas_limit
5. Execute function with ContractStorage
6. If success: commit storage changes, deduct gas
7. If failure: revert all changes
Intérprete EVM
El módulo evm_interpreter proporciona ejecución básica de bytecode EVM para compatibilidad con contratos de Ethereum. Esto permite desplegar contratos compilados con Solidity en Savitri.
Monitoreo de Memoria
El memory_monitor rastrea el uso de memoria en tiempo de ejecución para prevenir ataques DoS:
- Límites de memoria por contrato
- Seguimiento de asignaciones
- Terminación automática si se superan los límites
Ejecución Paralela
El módulo parallel habilita la ejecución paralela de contratos para transacciones independientes:
- Análisis de dependencias entre transacciones
- Detección de conflictos en ranuras de almacenamiento
- Ejecución paralela de transacciones sin conflictos
- Respaldo serial para transacciones conflictivas
Trazado de Contratos
El módulo tracing proporciona trazas de ejecución para depuración:
- Registro de ejecución paso a paso
- Seguimiento de lecturas/escrituras en almacenamiento
- Consumo de gas por operación
- Registro de emisión de eventos