Saltar al contenido principal

Contexto de Ejecución

En el corazón palpitante de cada ejecución de contrato inteligente en KodeChain reside el ExecutionContext, una estructura rica y dinámica implementada en vm/core/context.go que mantiene todo el estado necesario para que un contrato cobre vida. Este contexto no es solo un contenedor de datos; es el alma misma de la ejecución determinista.

Arquitectura del Contexto

ExecutionContext: El Núcleo de la Ejecución

type ExecutionContext struct {
// Contract information
ContractAddress string
Caller string
Origin string
Value *big.Int
GasLimit uint64

// Transaction information
TxHash string

// Block information
BlockNumber uint64
BlockTimestamp int64
BlockHash string
BlockDifficulty *big.Int
Coinbase string

// Execution state
PC uint64
Gas uint64
GasUsed uint64
Stack *Stack
Memory *Memory
Storage *Storage
ReturnData []byte
CallDepth int
IsStatic bool
HasReverted bool
ExecutionTime time.Duration

// Input/Output
Input []byte
Output []byte

// Logs
Logs []Log

// Consensus type
ConsensusType string
}

Esta estructura comprehensiva captura todos los aspectos de la ejecución de un contrato inteligente.

Información del Contrato

Identidad y Origen

ContractAddress string  // Dirección del contrato ejecutándose
Caller string // Quién llama al contrato
Origin string // Origen original de la transacción
Value *big.Int // Valor enviado con la llamada

Estos campos establecen la identidad del contrato y el contexto de la llamada, cruciales para la lógica de autorización y el seguimiento de fondos.

Límites de Gas

GasLimit uint64 // Límite máximo de gas
Gas uint64 // Gas restante
GasUsed uint64 // Gas consumido

El gas controla los recursos computacionales, previniendo bucles infinitos y ataques DoS.

Información del Bloque

Contexto Temporal

BlockNumber     uint64     // Número del bloque actual
BlockTimestamp int64 // Timestamp del bloque
BlockHash string // Hash del bloque
BlockDifficulty *big.Int // Dificultad (0 para PoS/PBFT)
Coinbase string // Dirección del validador

Esta información conecta la ejecución del contrato con el estado global de la blockchain.

Estado de Ejecución

Máquina Virtual Interna

PC      uint64    // Program Counter
Stack *Stack // Stack de 256 bits
Memory *Memory // Memoria expandible
Storage *Storage // Storage persistente

Estos componentes forman la máquina virtual interna que ejecuta el bytecode.

Control de Flujo

CallDepth     int  // Profundidad de llamadas
IsStatic bool // Llamada estática (solo lectura)
HasReverted bool // Si la ejecución revirtió
ExecutionTime time.Duration // Tiempo de ejecución

Estos campos controlan el flujo de ejecución y previenen ataques recursivos.

Entrada y Salida

Datos de la Llamada

Input  []byte // Datos de entrada (calldata)
Output []byte // Datos de salida (returndata)

Input contiene los parámetros de la función llamada, Output contiene los resultados.

Sistema de Logs

Eventos Emitidos

type Log struct {
Address string
Topics []string
Data []byte
}

Los logs permiten que los contratos emitan eventos indexados que pueden ser consultados por aplicaciones externas.

Gestión de Gas

Consumo Controlado

func (ctx *ExecutionContext) ConsumeGas(amount uint64) error {
if ctx.Gas < amount {
return ErrOutOfGas
}
ctx.Gas -= amount
ctx.GasUsed += amount
return nil
}

Cada operación consume gas, asegurando que la ejecución tenga límites computacionales.

Reembolso de Gas

func (ctx *ExecutionContext) RefundGas(amount uint64) {
ctx.Gas += amount
if ctx.GasUsed >= amount {
ctx.GasUsed -= amount
} else {
ctx.GasUsed = 0
}
}

Operaciones eficientes pueden recibir reembolso de gas.

Configuración del Bloque

Información Contextual

func (ctx *ExecutionContext) SetBlockInfo(number uint64, timestamp int64, hash, coinbase string) {
ctx.BlockNumber = number
ctx.BlockTimestamp = timestamp
ctx.BlockHash = hash
ctx.Coinbase = coinbase
}

Esta función configura el contexto con información del bloque actual.

Profundidad de Llamadas

Prevención de Recursión Infinita

func (ctx *ExecutionContext) IncrementCallDepth() error {
if ctx.CallDepth >= MaxCallDepth {
return ErrCallDepthExceeded
}
ctx.CallDepth++
return nil
}

Límite de 1024 llamadas anidadas previene ataques de recursión.

Reset y Clonación

Preparación para Nueva Ejecución

func (ctx *ExecutionContext) Reset() {
ctx.PC = 0
ctx.Gas = ctx.GasLimit
ctx.GasUsed = 0
ctx.Stack.Reset()
ctx.Memory.Reset()
ctx.ReturnData = []byte{}
ctx.Logs = make([]Log, 0)
ctx.HasReverted = false
ctx.CallDepth = 0
}

Reset prepara el contexto para una nueva ejecución, limpiando todo el estado efímero.

Clonación para Sub-llamadas

func (ctx *ExecutionContext) Clone() *ExecutionContext {
newCtx := &ExecutionContext{
ContractAddress: ctx.ContractAddress,
Caller: ctx.Caller,
Origin: ctx.Origin,
Value: new(big.Int).Set(ctx.Value),
GasLimit: ctx.Gas,
GasPrice: new(big.Int).Set(ctx.GasPrice),
// ... copiar otros campos
Stack: NewStack(),
Memory: NewMemory(),
Storage: ctx.Storage.Copy(),
Logs: make([]Log, 0),
CallDepth: ctx.CallDepth + 1,
}
return newCtx
}

Clone crea un contexto independiente para llamadas anidadas, manteniendo el estado del storage padre.

Sistema de Eventos

Emisión de Logs

func (ctx *ExecutionContext) AddLog(topics []string, data []byte) error {
if ctx.IsStatic {
return ErrWriteProtection
}

log := Log{
Address: ctx.ContractAddress,
Topics: topics,
Data: data,
}

ctx.Logs = append(ctx.Logs, log)
return nil
}

Los contratos pueden emitir eventos que son indexados y consultables.

Integración con la VM

Ciclo de Ejecución

func (vm *VM) Execute(bytecode []byte, input []byte) ([]byte, error) {
ctx := NewExecutionContext(contractAddr, caller, origin, value, gasLimit)
ctx.Input = input

for ctx.PC < uint64(len(bytecode)) {
opcode := bytecode[ctx.PC]
ctx.PC++

if err := vm.executeOpcode(ctx, opcode); err != nil {
return nil, err
}
}

return ctx.Output, nil
}

El contexto guía toda la ejecución, manteniendo el estado consistente.

Seguridad por Diseño

Aislamiento Completo

Cada ejecución tiene su propio contexto, previniendo interferencias entre contratos.

Validaciones Rigurosas

  • Gas suficiente antes de cada operación
  • Límites de memoria y stack
  • Profundidad de llamadas controlada
  • Protección contra escritura en llamadas estáticas

Determinismo Garantizado

Mismas entradas producen mismos resultados, esencial para la consistencia blockchain.

El Rol del Contexto

Puente entre Mundo y Contrato

El ExecutionContext sirve como puente entre:

  • El mundo externo: Transacciones, bloques, usuarios
  • El mundo interno: Stack, memoria, storage del contrato

Estado de Máquina Virtual

Mantiene el estado completo de la máquina virtual durante la ejecución:

  • Contadores de programa
  • Recursos disponibles
  • Estado de componentes
  • Resultados de operaciones

Contexto de Seguridad

Proporciona el contexto necesario para validaciones de seguridad:

  • Autorización de operaciones
  • Límites de recursos
  • Prevención de ataques

Filosofía de Diseño

Riqueza vs Simplicidad

El contexto es rico en información pero simple en uso, proporcionando todo lo necesario sin complejidad innecesaria.

Eficiencia en Memoria

Campos lazy-loaded y estructuras optimizadas para minimizar uso de memoria.

Extensibilidad

Diseño modular permite agregar nuevos campos sin romper compatibilidad.

El Arte del Estado

Cada ExecutionContext representa un momento congelado en el tiempo de ejecución de un contrato inteligente. Es el estado vivo que transforma código estático en ejecución dinámica, el puente entre la intención del desarrollador y la realidad de la blockchain.

En KodeChain, el contexto de ejecución no es solo una estructura de datos; es el alma misma de la computación distribuida, el guardián del estado que hace posible la magia de los contratos inteligentes.