语言参考
编写策略的 Rego 语法和语言特性完整指南
策略使用 Rego 编写,这是一种声明式策略语言,专为表达复杂的访问控制决策而设计。与命令式语言描述如何计算结果不同,Rego 允许您描述什么条件应触发策略决策。本页涵盖 256 Blocks 支持的所有语法和语言特性。
策略结构
您编写的每个策略都会由 256 Blocks 自动包装必要的样板代码。这意味着您可以专注于编写规则,而无需担心包声明或默认值。
所有策略:
- 自动包装必要的
package语句 - 预设
default deny := false(默认允许) - 预设
default denyGasSponsor := false(默认赞助) - 只能定义规则,不能覆盖默认值
基本规则语法
规则是策略的构建块。规则由头部(规则名称,例如:deny 或 denyGasSponsor)和主体(条件)组成。当主体中的所有条件都为真时,规则评估为 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
}辅助规则
除了 deny 和 denyGasSponsor 之外,您还可以定义自己的自定义规则来组织复杂逻辑。辅助规则充当可重用的构建块,使您的策略更易读和可维护。
辅助规则只是一个命名条件,当其主体匹配时评估为 true。然后,您可以在 deny 或 denyGasSponsor 规则中引用这些规则,包括使用 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.chain、input.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
}