Contratos Inteligentes
Introducción
KodeChain incluye una máquina virtual completa que soporta contratos inteligentes similares a Ethereum pero con mejoras en seguridad, debugging y post-quantum cryptography.
Características de la VM
Stack Machine de 256 bits
- Máximo 1024 elementos en stack
- Operaciones con números de 256 bits
- Push/Pop/Dup/Swap completos
Memoria Expandible
- Máximo 16 MB
- Expansión automática en chunks de 32 bytes
- Load/Store/Copy operations
Storage Persistente
- Key-value store por contrato
- Thread-safe con mutex
- Persistencia en blockchain
Sistema de Gas
- Límite configurable (default: 10M gas)
- Costos por opcode
- Prevención de DoS
Arquitectura
┌─────────────────────────────────────────┐
│ Smart Contract │
│ ┌───────────────────────────────────┐ │
│ │ Bytecode (Opcodes) │ │
│ └───────────────────────────────────┘ │
│ ┌───────────────────────────────────┐ │
│ │ ABI (Function Selectors) │ │
│ └───────────────────────────────────┘ │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Virtual Machine (VM) │
│ ┌──────────┐ ┌─────────┐ ┌──────────┐ │
│ │ Stack │ │ Memory │ │ Storage │ │
│ └──────────┘ └─────────┘ └──────────┘ │
│ ┌──────────────────────────────────┐ │
│ │ Opcode Execution Engine │ │
│ └──────────────────────────────────┘ │
│ ┌──────────────────────────────────┐ │
│ │ Gas Metering │ │
│ └──────────────────────────────────┘ │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ Blockchain │
│ - State Storage │
│ - Event Logs │
│ - Transaction History │
└─────────────────────────────────────────┘
Escribir tu Primer Contrato
Ejemplo: Almacenamiento Simple
; Simple Storage Contract
; Almacena y recupera un valor
; Constructor
CONSTRUCTOR:
PUSH1 0x00 ; slot 0
PUSH1 0x00 ; valor inicial 0
SSTORE ; storage[0] = 0
STOP
; Function: store(uint256 value)
; Selector: 0x12345678
STORE:
; Obtener valor del calldata
PUSH1 0x04 ; offset 4 (después del selector)
CALLDATALOAD ; cargar valor
; Almacenar en storage
PUSH1 0x00 ; slot 0
SSTORE ; storage[0] = value
; Emitir evento
PUSH1 0x20 ; size
PUSH1 0x00 ; offset
LOG1 ; emit ValueStored(value)
STOP
; Function: retrieve() returns (uint256)
; Selector: 0x9abcdef0
RETRIEVE:
; Cargar valor del storage
PUSH1 0x00 ; slot 0
SLOAD ; value = storage[0]
; Almacenar en memoria para return
PUSH1 0x00 ; offset 0
MSTORE ; memory[0] = value
; Return
PUSH1 0x20 ; size (32 bytes)
PUSH1 0x00 ; offset
RETURN
Compilar Contrato
package main
import (
"kodechain/vm/compiler"
)
func main() {
code := `
CONSTRUCTOR:
PUSH1 0x00
PUSH1 0x00
SSTORE
STOP
STORE:
PUSH1 0x04
CALLDATALOAD
PUSH1 0x00
SSTORE
STOP
RETRIEVE:
PUSH1 0x00
SLOAD
PUSH1 0x00
MSTORE
PUSH1 0x20
PUSH1 0x00
RETURN
`
bytecode, err := compiler.Compile(code)
if err != nil {
panic(err)
}
// bytecode listo para deployment
}
Sistema ABI
Function Selectors
KodeChain usa SHA-256 (primeros 4 bytes) en lugar de Keccak-256:
// Calcular selector
functionSig := "store(uint256)"
hash := sha256.Sum256([]byte(functionSig))
selector := hash[:4] // 0x12345678
Encoding de Parámetros
// Encode una llamada a función
abi := &vm.ABI{
Functions: []vm.Function{
{
Name: "store",
Inputs: []vm.Parameter{
{Name: "value", Type: "uint256"},
},
},
},
}
// Encode la llamada
data, err := abi.EncodeFunctionCall("store", []interface{}{
big.NewInt(42),
})
// data = 0x12345678000000000000000000000000000000000000000000000000000000000000002a
// ^selector ^value (42 en hex = 0x2a)
Deploy de Contrato
Método 1: API REST
curl -X POST http://localhost:8545/api/contracts/deploy \
-H "Content-Type: application/json" \
-d '{
"from": "0xYourAddress",
"bytecode": "0x608060405234801561001057600080fd5b50...",
"abi": [{...}],
"constructor_args": [],
"gas_limit": 3000000,
"private_key": "your_private_key"
}'
Respuesta:
{
"success": true,
"contract_address": "0x1234567890abcdef1234567890abcdef12345678",
"tx_hash": "0xabc123...",
"gas_used": 250000
}
Método 2: Usando SDK (Go)
// Crear deployer
deployer := contract.NewDeployer(blockchain, mempool)
// Deploy contrato
contractAddr, err := deployer.Deploy(
from,
bytecode,
constructorArgs,
gasLimit,
)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Contract deployed at: %s\n", contractAddr)
Llamar a Contrato
Método 1: API REST
curl -X POST http://localhost:8545/api/contracts/call \
-H "Content-Type: application/json" \
-d '{
"from": "0xYourAddress",
"to": "0xContractAddress",
"function": "store",
"args": [42],
"gas_limit": 100000,
"private_key": "your_private_key"
}'
Método 2: Usando SDK
// Preparar llamada
callData, _ := abi.EncodeFunctionCall("store", []interface{}{
big.NewInt(42),
})
// Ejecutar
executor := contract.NewExecutor(vm, blockchain)
result, err := executor.Call(
from,
contractAddr,
callData,
gasLimit,
)
if err != nil {
log.Fatal(err)
}
Eventos y Logs
Emitir Evento
; Preparar datos en memoria
PUSH32 0x000000000000000000000000000000000000000000000000000000000000002a
PUSH1 0x00
MSTORE
; Preparar topics
PUSH32 0x1234... ; Event signature
PUSH32 0x5678... ; Topic 1
; Emitir evento
PUSH1 0x20 ; size
PUSH1 0x00 ; offset
LOG2 ; 2 topics
Escuchar Eventos
// Crear filtro
filter := events.NewLogFilter(blockchain)
query := &events.FilterQuery{
FromBlock: 100,
ToBlock: 200,
Addresses: []string{"0xContractAddress"},
Topics: [][]string{
{"0x1234..."}, // Event signature
},
}
// Obtener logs
logs := filter.FilterLogs(query)
for _, log := range logs {
fmt.Printf("Event: %s\n", log.Topics[0])
fmt.Printf("Data: %s\n", log.Data)
}
Debugging
Debugger
// Crear debugger
debugger := debug.NewDebugger(vm)
// Establecer breakpoint
debugger.AddBreakpoint(50) // en PC = 50
// Ejecutar en modo debug
debugger.StepInto()
debugger.StepOver()
// Inspeccionar estado
stack := debugger.GetStack()
memory := debugger.GetMemory()
storage := debugger.GetStorage()
Tracer
// Crear tracer
tracer := debug.NewTracer()
// Ejecutar contrato con tracing
vm.SetTracer(tracer)
vm.Execute(bytecode, callData)
// Obtener trace
trace := tracer.GetExecutionTrace()
for _, step := range trace {
fmt.Printf("PC: %d, Opcode: %s, Gas: %d\n",
step.PC, step.Opcode, step.GasUsed)
}
Profiler
// Perfilar ejecución
profiler := debug.NewProfiler()
vm.SetProfiler(profiler)
vm.Execute(bytecode, callData)
// Análisis de performance
report := profiler.GetReport()
fmt.Println("Top Opcodes by Gas:")
for _, item := range report.TopOpcodesByGas {
fmt.Printf("%s: %d gas\n", item.Opcode, item.TotalGas)
}
Límites y Seguridad
Sandbox Configuration
sandbox := &vm.SandboxConfig{
MaxGas: 10000000, // 10M gas
MaxExecutionTime: 60 * time.Second,
MaxMemory: 16 * 1024 * 1024, // 16 MB
MaxStackDepth: 1024,
MaxCallDepth: 1024,
MaxCodeSize: 24576, // 24 KB
}
vm := vm.NewVM(sandbox)
Prevención de Vulnerabilidades
- Reentrancy: VM no soporta calls externos aún
- Integer Overflow: Usar SafeMath en contratos
- Gas Limit: Límites configurables
- Timeout: Ejecución limitada por tiempo
Ejemplos Completos
Ver documentación de ejemplos:
Próximos Pasos
Construye contratos inteligentes seguros y eficientes en KodeChain