语言参考

编写策略的 Rego 语法和语言特性完整指南

策略使用 Rego 编写,这是一种声明式策略语言,专为表达复杂的访问控制决策而设计。与命令式语言描述如何计算结果不同,Rego 允许您描述什么条件应触发策略决策。本页涵盖 256 Blocks 支持的所有语法和语言特性。

策略结构

您编写的每个策略都会由 256 Blocks 自动包装必要的样板代码。这意味着您可以专注于编写规则,而无需担心包声明或默认值。

所有策略:

  • 自动包装必要的 package 语句
  • 预设 default deny := false(默认允许)
  • 预设 default denyGasSponsor := false(默认赞助)
  • 只能定义规则,不能覆盖默认值

基本规则语法

规则是策略的构建块。规则由头部(规则名称,例如:denydenyGasSponsor)和主体(条件)组成。当主体中的所有条件都为真时,规则评估为 true

示例

# Basic structure: rule_name if { conditions }
deny if {
    input.usd_value > 10000
}

多个条件(AND 逻辑)

当您在同一规则主体中包含多个条件时,所有条件都必须为真才能触发规则。每个条件都隐式地用 AND 连接。

示例

# Both conditions must be true to deny
deny if {
    input.chain == "ethereum"
    input.usd_value > 1000
}

多个规则(OR 逻辑)

当您定义多个同名规则时,任何匹配的规则都会触发策略。这在规则之间提供了 OR 逻辑。

示例

# Either condition triggers denial
deny if {
    input.chain == "ethereum"
}
 
deny if {
    input.usd_value > 10000
}

结合 AND 和 OR

您可以结合这两种模式来实现复杂逻辑。每个规则主体内部使用 AND 逻辑,而多个规则之间提供 OR 逻辑。

示例

# 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"}
}

变量赋值

使用 := 运算符为变量赋值。变量通过为值提供有意义的名称并实现重用,使您的策略更易读和可维护。

策略级变量

在规则主体外定义的变量充当常量,可以被多个规则引用。使用这些来设置阈值、白名单和黑名单。

示例

# 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
}

局部变量

在规则主体内定义的变量是该规则的局部变量。使用这些进行中间计算或提高可读性。

示例

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
}

比较运算符

Rego 提供标准比较运算符用于评估条件。这些运算符适用于字符串、数字和其他可比较类型。

运算符描述示例
==等于input.chain == "ethereum"
!=不等于input.chain != "polygon"
>大于input.usd_value > 1000
>=大于或等于input.usd_value >= 1000
<小于input.usd_value < 100
<=小于或等于input.usd_value <= 100

示例

# 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
}

算术运算符

您可以在策略条件中执行算术计算。这对于计算阈值、应用乘数或组合值非常有用。

运算符描述示例
+加法input.usd_value + 100
-减法input.usd_value - fees
*乘法input.usd_value * 1.1
/除法input.usd_value / 2
%取模(余数)input.gas_limit % 1000

示例

# 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
}

逻辑运算符

除了隐式 AND(多个条件)和 OR(多个规则)之外,Rego 还提供显式逻辑运算符用于更复杂的表达式。

not 运算符

使用 not 来否定条件。这对于白名单模式特别有用,在这种模式下,您希望拒绝不在允许集合中的任何内容。

示例

# Only allow specific chains (deny everything else)
allowed_chains := {"polygon", "base", "arbitrum"}
 
deny if {
    not input.chain in allowed_chains
}

示例:与其他条件结合

# 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
}

辅助规则

除了 denydenyGasSponsor 之外,您还可以定义自己的自定义规则来组织复杂逻辑。辅助规则充当可重用的构建块,使您的策略更易读和可维护。

辅助规则只是一个命名条件,当其主体匹配时评估为 true。然后,您可以在 denydenyGasSponsor 规则中引用这些规则,包括使用 not 运算符来否定它们。

示例

# 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
}

辅助规则特别适用于:

  • 可重用性:定义一次条件,在多个规则中使用
  • 可读性:为复杂条件提供有意义的名称
  • 否定:使用 not 检查条件何时不满足
  • 组织:将复杂策略分解为逻辑组件

字符串操作

字符串是用双引号("")括起来的字符序列。大多数输入字段如 input.chaininput.rpc_method 和地址都是字符串。Rego 提供了几个用于处理字符串的内置函数,这对于地址、方法名称和其他文本字段的模式匹配至关重要。

函数描述返回值
contains(string, substring)检查字符串是否包含子字符串boolean
startswith(string, prefix)检查字符串是否以前缀开头boolean
endswith(string, suffix)检查字符串是否以后缀结尾boolean
lower(string)转换为小写string
upper(string)转换为大写string
substring(string, start, length)提取字符串的一部分string
sprintf(format, values)使用值格式化字符串string

示例

# 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_")
}

数组操作

数组是有序的值列表,用方括号 [] 定义。与集合不同,数组保留元素的顺序并可以包含重复项。您将在策略中频繁使用数组,尤其是包含请求中涉及的所有合约地址的 input.contract_addresses

# Array syntax
my_array := ["first", "second", "third"]

Rego 提供了几种检查和处理数组的方法。

函数描述返回值
count(array)元素数量number
array[index]按索引访问元素(从 0 开始)element
value in array检查值是否存在于数组中boolean

示例

# 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")
}

成员测试

成员测试是策略中最常见的操作之一。您将使用它来检查值是否属于白名单、黑名单或其他允许值的集合。

集合

集合是无序的唯一值集合,用花括号 {} 定义。使用 in 运算符测试值是否存在于集合中。

# Set syntax
my_set := {"value1", "value2", "value3"}

集合针对快速成员测试进行了优化,使其成为白名单和黑名单的理想选择。

示例

# 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
}

内联集合与命名集合

您可以在规则中内联定义集合,也可以在策略级别定义为命名变量。命名集合提高了可读性并允许跨多个规则重用。

示例

# 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
}

使用 some 进行迭代

some 关键字允许您遍历集合并针对每个元素检查条件。这在处理像 input.contract_addresses 这样的数组时至关重要。

基本迭代

使用 some 检查集合中的任何元素是否匹配条件。

示例

# 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
}

带索引的迭代

您还可以在迭代期间访问每个元素的索引。

示例

# Check conditions on specific positions
deny if {
    some i, addr in input.contract_addresses
    i == 0  # First contract only
    startswith(addr, "0x000")
}

示例:查找任何匹配

# 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
}

使用 every 进行迭代

虽然 some 检查任何元素是否匹配,但 every 要求所有元素都匹配条件。这对于确保整个集合满足您的标准很有用。

示例

# 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)
    }
}

示例:验证模式

# 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
    }
}

推导式

推导式允许您通过转换或过滤现有集合来创建新集合。它们对于提取特定值或构建派生数据集很有用。

数组推导式

从符合特定条件的元素创建新数组。

示例

# 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
}

集合推导式

创建唯一值的集合。

示例

# 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

else 关键字允许您在条件不满足时定义后备值。这对于计算基于输入变化的派生值很有用。

示例

# 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"}
}

示例:特定链的阈值

# 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
}
语言参考 | 256 Blocks