Referencia del Lenguaje
Guía completa de sintaxis Rego y características del lenguaje para escribir políticas
Las políticas están escritas en Rego, un lenguaje de políticas declarativo diseñado para expresar decisiones complejas de control de acceso. A diferencia de los lenguajes imperativos donde describes cómo calcular un resultado, Rego te permite describir qué condiciones deben activar una decisión de política. Esta página cubre toda la sintaxis y características del lenguaje soportadas en 256 Blocks.
Estructura de Políticas
Cada política que escribes se envuelve automáticamente con el código repetitivo necesario por 256 Blocks. Esto significa que puedes enfocarte puramente en escribir tus reglas sin preocuparte por declaraciones de paquetes o valores predeterminados.
Todas las políticas:
- Se envuelven automáticamente con la declaración
packagenecesaria - Tienen un
default deny := falsepredefinido (permitir por defecto) - Tienen un
default denyGasSponsor := falsepredefinido (patrocinar por defecto) - Solo pueden definir reglas, no anular valores predeterminados
Sintaxis Básica de Reglas
Las reglas son los bloques de construcción de las políticas. Una regla consiste en una cabecera (el nombre de la regla, ej: deny o denyGasSponsor) y un cuerpo (las condiciones). Cuando todas las condiciones en el cuerpo son verdaderas, la regla se evalúa como true.
Ejemplo
# Basic structure: rule_name if { conditions }
deny if {
input.usd_value > 10000
}Múltiples Condiciones (Lógica AND)
Cuando incluyes múltiples condiciones en el mismo cuerpo de regla, TODAS las condiciones deben ser verdaderas para que la regla se active. Cada condición se une implícitamente con AND.
Ejemplo
# Both conditions must be true to deny
deny if {
input.chain == "ethereum"
input.usd_value > 1000
}Múltiples Reglas (Lógica OR)
Cuando defines múltiples reglas con el mismo nombre, CUALQUIER regla coincidente activará la política. Esto proporciona lógica OR entre reglas.
Ejemplo
# Either condition triggers denial
deny if {
input.chain == "ethereum"
}
deny if {
input.usd_value > 10000
}Combinando AND y OR
Puedes combinar ambos patrones para lógica compleja. Cada cuerpo de regla usa lógica AND internamente, mientras que múltiples reglas proporcionan lógica OR entre ellas.
Ejemplo
# Deny if: (ethereum AND high-value) OR (any chain AND blocked country)
deny if {
input.chain == "ethereum"
input.usd_value > 5000
}
deny if {
input.source_country in {"KP", "IR", "CU"}
}Asignación de Variables
Usa el operador := para asignar valores a variables. Las variables hacen que tus políticas sean más legibles y mantenibles al dar nombres significativos a los valores y permitir la reutilización.
Variables a Nivel de Política
Las variables definidas fuera de los cuerpos de reglas actúan como constantes que pueden ser referenciadas por múltiples reglas. Úsalas para umbrales, listas blancas y listas negras.
Ejemplo
# Policy-level constants - defined once, used everywhere
max_transaction_value := 50000
blocked_countries := {"KP", "IR", "CU", "SY"}
approved_senders := {"0x742d35cc...", "0xa0b86991..."}
deny if {
input.usd_value > max_transaction_value
}
deny if {
input.source_country in blocked_countries
}
deny if {
not input.from_address in approved_senders
}Variables Locales
Las variables definidas dentro del cuerpo de una regla son locales a esa regla. Úsalas para cálculos intermedios o para mejorar la legibilidad.
Ejemplo
deny if {
# Calculate with a safety margin
value_with_buffer := input.usd_value * 1.15
value_with_buffer > 10000
}
deny if {
# Estimate gas cost in wei
gas_cost := to_number(input.gas_limit) * to_number(input.max_fee_per_gas)
gas_cost > 1000000000000000000 # 1 ETH in wei
}Operadores de Comparación
Rego proporciona operadores de comparación estándar para evaluar condiciones. Estos funcionan con cadenas, números y otros tipos comparables.
| Operador | Descripción | Ejemplo |
|---|---|---|
== | Igual a | input.chain == "ethereum" |
!= | No igual a | input.chain != "polygon" |
> | Mayor que | input.usd_value > 1000 |
>= | Mayor o igual que | input.usd_value >= 1000 |
< | Menor que | input.usd_value < 100 |
<= | Menor o igual que | input.usd_value <= 100 |
Ejemplo
# Block high-value transactions on expensive chains
deny if {
input.chain == "ethereum"
input.usd_value >= 5000
}
# Block transactions below a minimum value (potential spam)
deny if {
input.usd_value != null
input.usd_value < 1
}Operadores Aritméticos
Puedes realizar cálculos aritméticos dentro de las condiciones de tu política. Esto es útil para calcular umbrales, aplicar multiplicadores o combinar valores.
| Operador | Descripción | Ejemplo |
|---|---|---|
+ | Suma | input.usd_value + 100 |
- | Resta | input.usd_value - fees |
* | Multiplicación | input.usd_value * 1.1 |
/ | División | input.usd_value / 2 |
% | Módulo (resto) | input.gas_limit % 1000 |
Ejemplo
# Apply a 10% buffer when checking limits
deny if {
input.usd_value * 1.1 > 10000
}
# Block if combined value exceeds threshold
deny if {
total := input.usd_value + 500 # Add estimated fees
total > 5000
}Operadores Lógicos
Además del AND implícito (múltiples condiciones) y OR (múltiples reglas), Rego proporciona operadores lógicos explícitos para expresiones más complejas.
El Operador not
Usa not para negar una condición. Esto es particularmente útil para patrones de lista blanca donde quieres denegar cualquier cosa que NO esté en un conjunto permitido.
Ejemplo
# Only allow specific chains (deny everything else)
allowed_chains := {"polygon", "base", "arbitrum"}
deny if {
not input.chain in allowed_chains
}Ejemplo: Combinando con Otras Condiciones
# Deny if NOT a read-only method AND value is high
deny if {
not input.rpc_method in {"eth_call", "eth_getBalance"}
input.usd_value > 1000
}Reglas Auxiliares
Además de deny y denyGasSponsor, puedes definir tus propias reglas personalizadas para organizar lógica compleja. Las reglas auxiliares actúan como bloques de construcción reutilizables que hacen tus políticas más legibles y mantenibles.
Una regla auxiliar es simplemente una condición nombrada que se evalúa como true cuando su cuerpo coincide. Luego puedes referenciar estas reglas en tus reglas deny o denyGasSponsor, incluyendo con el operador not para negarlas.
Ejemplo
# Define a helper rule to check if request is from a trusted source
is_trusted if {
input.source_country in {"US", "GB", "DE"}
input.source_ip in {"203.0.113.10", "203.0.113.11"}
}
# Define another helper for high-risk transactions
is_high_risk if {
input.usd_value > 10000
}
is_high_risk if {
input.source_country in {"RU", "CN"}
}
# Use helper rules in deny conditions
deny if {
not is_trusted
is_high_risk
}Las reglas auxiliares son particularmente útiles para:
- Reutilización: Define una condición una vez, úsala en múltiples reglas
- Legibilidad: Da nombres significativos a condiciones complejas
- Negación: Usa
notpara verificar cuando una condición NO se cumple - Organización: Descompone políticas complejas en componentes lógicos
Operaciones con Cadenas
Las cadenas son secuencias de caracteres encerradas entre comillas dobles (""). La mayoría de los campos de entrada como input.chain, input.rpc_method y direcciones son cadenas. Rego proporciona varias funciones integradas para trabajar con cadenas, esenciales para la coincidencia de patrones en direcciones, nombres de métodos y otros campos de texto.
| Función | Descripción | Retorna |
|---|---|---|
contains(string, substring) | Verifica si la cadena contiene la subcadena | boolean |
startswith(string, prefix) | Verifica si la cadena comienza con el prefijo | boolean |
endswith(string, suffix) | Verifica si la cadena termina con el sufijo | boolean |
lower(string) | Convierte a minúsculas | string |
upper(string) | Convierte a mayúsculas | string |
substring(string, start, length) | Extrae una porción de la cadena | string |
sprintf(format, values) | Formatea cadena con valores | string |
Ejemplo
# Block any method containing "sign" (covers eth_sign, personal_sign, etc.)
deny if {
contains(input.rpc_method, "sign")
}
# Block addresses starting with known malicious prefix
deny if {
startswith(lower(input.to_address), "0x000000000000000000000000000000000000dead")
}
# Block debug and admin methods
deny if {
startswith(input.rpc_method, "debug_")
}
deny if {
startswith(input.rpc_method, "admin_")
}Operaciones con Arrays
Los arrays son listas ordenadas de valores, definidas con corchetes []. A diferencia de los conjuntos, los arrays preservan el orden de los elementos y pueden contener duplicados. Trabajarás frecuentemente con arrays en políticas, especialmente input.contract_addresses que contiene todas las direcciones de contratos involucradas en una solicitud.
# Array syntax
my_array := ["first", "second", "third"]Rego proporciona varias formas de inspeccionar y trabajar con arrays.
| Función | Descripción | Retorna |
|---|---|---|
count(array) | Número de elementos | number |
array[index] | Acceder elemento por índice (basado en 0) | element |
value in array | Verificar si el valor existe en el array | boolean |
Ejemplo
# Limit the number of contracts in a single request
deny if {
count(input.contract_addresses) > 10
}
# Check if a specific address is in the contract list
deny if {
"0xbanned..." in input.contract_addresses
}
# Access specific array elements
deny if {
count(input.contract_addresses) > 0
first_contract := input.contract_addresses[0]
startswith(first_contract, "0xdead")
}Prueba de Membresía
La prueba de membresía es una de las operaciones más comunes en políticas. La usarás para verificar si los valores pertenecen a listas blancas, listas negras u otras colecciones de valores permitidos.
Conjuntos
Los conjuntos son colecciones no ordenadas de valores únicos, definidas con llaves {}. Usa el operador in para probar si un valor existe en un conjunto.
# Set syntax
my_set := {"value1", "value2", "value3"}Los conjuntos están optimizados para pruebas rápidas de membresía, haciéndolos ideales para listas blancas y listas negras.
Ejemplo
# Block requests from sanctioned countries
blocked_countries := {"KP", "IR", "CU", "SY", "RU"}
deny if {
input.source_country in blocked_countries
}
# Only allow specific chains
allowed_chains := {"polygon", "base", "arbitrum"}
deny if {
not input.chain in allowed_chains
}Conjuntos en Línea vs Conjuntos Nombrados
Puedes definir conjuntos en línea dentro de reglas o como variables nombradas a nivel de política. Los conjuntos nombrados mejoran la legibilidad y permiten la reutilización en múltiples reglas.
Ejemplo
# Inline set - good for simple, one-off checks
deny if {
input.rpc_method in {"eth_sign", "personal_sign", "eth_signTypedData"}
}
# Named set - better for reusability and readability
approved_contracts := {
"0xdac17f958d2ee523a2206206994597c13d831ec7", # USDT
"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", # USDC
"0x6b175474e89094c44da98b954eedeac495271d0f" # DAI
}
deny if {
some addr in input.contract_addresses
not addr in approved_contracts
}Iteración con some
La palabra clave some te permite iterar sobre colecciones y verificar condiciones contra cada elemento. Esto es esencial cuando trabajas con arrays como input.contract_addresses.
Iteración Básica
Usa some para verificar si CUALQUIER elemento en una colección coincide con una condición.
Ejemplo
# Deny if ANY contract address is in the blocklist
blocked_contracts := {"0xbanned1...", "0xbanned2..."}
deny if {
some addr in input.contract_addresses
addr in blocked_contracts
}Iteración con Índice
También puedes acceder al índice de cada elemento durante la iteración.
Ejemplo
# Check conditions on specific positions
deny if {
some i, addr in input.contract_addresses
i == 0 # First contract only
startswith(addr, "0x000")
}Ejemplo: Encontrando Cualquier Coincidencia
# Deny if any contract starts with a suspicious prefix
deny if {
some addr in input.contract_addresses
startswith(lower(addr), "0x000000000000000000000000")
}
# Deny if any contract is not in the approved list
approved := {"0xusdt...", "0xusdc...", "0xdai..."}
deny if {
some addr in input.contract_addresses
not addr in approved
}Iteración con every
Mientras que some verifica si CUALQUIER elemento coincide, every requiere que TODOS los elementos coincidan con una condición. Esto es útil para asegurar que colecciones enteras cumplan tus criterios.
Ejemplo
# Deny only if ALL contracts are from a suspicious set
# (unlikely to be legitimate if every address is suspicious)
suspicious_prefixes := {"0x0000000000000000"}
deny if {
count(input.contract_addresses) > 0
every addr in input.contract_addresses {
some prefix in suspicious_prefixes
startswith(addr, prefix)
}
}Ejemplo: Patrones de Validación
# Ensure all contracts are from approved list (inverse of some/not)
approved_contracts := {"0xusdt...", "0xusdc...", "0xdai..."}
# This denies if ANY contract is not approved
deny if {
some addr in input.contract_addresses
not addr in approved_contracts
}
# Equivalent using every (deny if NOT every contract is approved)
deny if {
count(input.contract_addresses) > 0
not every addr in input.contract_addresses {
addr in approved_contracts
}
}Comprensiones
Las comprensiones te permiten crear nuevas colecciones transformando o filtrando las existentes. Son útiles para extraer valores específicos o construir conjuntos de datos derivados.
Comprensión de Arrays
Crea un nuevo array a partir de elementos que cumplen ciertos criterios.
Ejemplo
# Extract all contract addresses that start with a specific prefix
matching_contracts := [addr |
some addr in input.contract_addresses
startswith(addr, "0xa")
]
deny if {
count(matching_contracts) > 3
}Comprensión de Conjuntos
Crea un conjunto de valores únicos.
Ejemplo
# Get unique prefixes from all contract addresses
contract_prefixes := {substring(addr, 0, 6) |
some addr in input.contract_addresses
}
# Deny if there are too many different contract prefixes (suspicious)
deny if {
count(contract_prefixes) > 5
}Else Condicional
La palabra clave else te permite definir valores de respaldo cuando las condiciones no se cumplen. Esto es útil para calcular valores derivados que varían según la entrada.
Ejemplo
# Assign risk level based on transaction value
risk_level := "critical" if {
input.usd_value > 100000
} else := "high" if {
input.usd_value > 10000
} else := "medium" if {
input.usd_value > 1000
} else := "low"
# Use the computed risk level in deny rules
deny if {
risk_level == "critical"
}
denyGasSponsor if {
risk_level in {"high", "critical"}
}Ejemplo: Umbrales Específicos por Cadena
# Different limits for different chains
chain_limit := 1000 if {
input.chain == "ethereum"
} else := 5000 if {
input.chain == "polygon"
} else := 10000
deny if {
input.usd_value > chain_limit
}