Referensi Bahasa
Panduan lengkap untuk sintaks Rego dan fitur bahasa untuk menulis kebijakan
Kebijakan ditulis dalam Rego, bahasa kebijakan deklaratif yang dirancang untuk mengekspresikan keputusan kontrol akses yang kompleks. Berbeda dengan bahasa imperatif di mana Anda mendeskripsikan bagaimana menghitung hasil, Rego memungkinkan Anda mendeskripsikan kondisi apa yang harus memicu keputusan kebijakan. Halaman ini mencakup semua sintaks dan fitur bahasa yang didukung di 256 Blocks.
Struktur Kebijakan
Setiap kebijakan yang Anda tulis secara otomatis dibungkus dengan boilerplate yang diperlukan oleh 256 Blocks. Ini berarti Anda dapat fokus murni pada menulis aturan Anda tanpa khawatir tentang deklarasi paket atau nilai default.
Semua kebijakan:
- Secara otomatis dibungkus dengan pernyataan
packageyang diperlukan - Memiliki preset
default deny := false(izinkan secara default) - Memiliki preset
default denyGasSponsor := false(sponsor secara default) - Hanya dapat menentukan aturan, tidak dapat mengganti default
Sintaks Aturan Dasar
Aturan adalah blok bangunan kebijakan. Aturan terdiri dari head (nama aturan, mis: deny atau denyGasSponsor) dan body (kondisi). Ketika semua kondisi dalam body benar, aturan dievaluasi menjadi true.
Contoh
# Struktur dasar: rule_name if { conditions }
deny if {
input.usd_value > 10000
}Beberapa Kondisi (Logika AND)
Ketika Anda menyertakan beberapa kondisi dalam body aturan yang sama, SEMUA kondisi harus benar agar aturan terpicu. Setiap kondisi secara implisit digabungkan dengan AND.
Contoh
# Kedua kondisi harus benar untuk deny
deny if {
input.chain == "ethereum"
input.usd_value > 1000
}Beberapa Aturan (Logika OR)
Ketika Anda menentukan beberapa aturan dengan nama yang sama, SETIAP aturan yang cocok akan memicu kebijakan. Ini menyediakan logika OR antar aturan.
Contoh
# Salah satu kondisi memicu penolakan
deny if {
input.chain == "ethereum"
}
deny if {
input.usd_value > 10000
}Menggabungkan AND dan OR
Anda dapat menggabungkan kedua pola untuk logika kompleks. Setiap body aturan menggunakan logika AND secara internal, sementara beberapa aturan menyediakan logika OR di antara mereka.
Contoh
# Deny jika: (ethereum AND nilai-tinggi) OR (rantai apa pun AND negara yang diblokir)
deny if {
input.chain == "ethereum"
input.usd_value > 5000
}
deny if {
input.source_country in {"KP", "IR", "CU"}
}Penugasan Variabel
Gunakan operator := untuk menugaskan nilai ke variabel. Variabel membuat kebijakan Anda lebih mudah dibaca dan dipelihara dengan memberikan nama yang bermakna pada nilai dan memungkinkan penggunaan kembali.
Variabel Tingkat Kebijakan
Variabel yang didefinisikan di luar body aturan bertindak sebagai konstanta yang dapat dirujuk oleh beberapa aturan. Gunakan ini untuk ambang batas, allowlist, dan blocklist.
Contoh
# Konstanta tingkat kebijakan - didefinisikan sekali, digunakan di mana saja
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
}Variabel Lokal
Variabel yang didefinisikan di dalam body aturan bersifat lokal untuk aturan tersebut. Gunakan ini untuk perhitungan perantara atau untuk meningkatkan keterbacaan.
Contoh
deny if {
# Hitung dengan margin keamanan
value_with_buffer := input.usd_value * 1.15
value_with_buffer > 10000
}
deny if {
# Perkirakan biaya gas dalam wei
gas_cost := to_number(input.gas_limit) * to_number(input.max_fee_per_gas)
gas_cost > 1000000000000000000 # 1 ETH dalam wei
}Operator Perbandingan
Rego menyediakan operator perbandingan standar untuk mengevaluasi kondisi. Ini bekerja dengan string, angka, dan tipe yang dapat dibandingkan lainnya.
| Operator | Deskripsi | Contoh |
|---|---|---|
== | Sama dengan | input.chain == "ethereum" |
!= | Tidak sama dengan | input.chain != "polygon" |
> | Lebih besar dari | input.usd_value > 1000 |
>= | Lebih besar dari atau sama dengan | input.usd_value >= 1000 |
< | Lebih kecil dari | input.usd_value < 100 |
<= | Lebih kecil dari atau sama dengan | input.usd_value <= 100 |
Contoh
# Blokir transaksi bernilai tinggi pada rantai mahal
deny if {
input.chain == "ethereum"
input.usd_value >= 5000
}
# Blokir transaksi di bawah nilai minimum (potensi spam)
deny if {
input.usd_value != null
input.usd_value < 1
}Operator Aritmatika
Anda dapat melakukan perhitungan aritmatika dalam kondisi kebijakan Anda. Ini berguna untuk menghitung ambang batas, menerapkan pengali, atau menggabungkan nilai.
| Operator | Deskripsi | Contoh |
|---|---|---|
+ | Penambahan | input.usd_value + 100 |
- | Pengurangan | input.usd_value - fees |
* | Perkalian | input.usd_value * 1.1 |
/ | Pembagian | input.usd_value / 2 |
% | Modulo (sisa) | input.gas_limit % 1000 |
Contoh
# Terapkan buffer 10% saat memeriksa batas
deny if {
input.usd_value * 1.1 > 10000
}
# Blokir jika nilai gabungan melebihi ambang batas
deny if {
total := input.usd_value + 500 # Tambahkan perkiraan biaya
total > 5000
}Operator Logika
Di luar AND implisit (beberapa kondisi) dan OR (beberapa aturan), Rego menyediakan operator logika eksplisit untuk ekspresi yang lebih kompleks.
Operator not
Gunakan not untuk menegasikan kondisi. Ini sangat berguna untuk pola allowlist di mana Anda ingin menolak apa pun yang TIDAK ada dalam set yang diizinkan.
Contoh
# Hanya izinkan rantai tertentu (tolak yang lainnya)
allowed_chains := {"polygon", "base", "arbitrum"}
deny if {
not input.chain in allowed_chains
}Contoh: Menggabungkan dengan Kondisi Lain
# Tolak jika BUKAN metode read-only DAN nilainya tinggi
deny if {
not input.rpc_method in {"eth_call", "eth_getBalance"}
input.usd_value > 1000
}Aturan Pembantu
Selain deny dan denyGasSponsor, Anda dapat menentukan aturan kustom Anda sendiri untuk mengorganisir logika kompleks. Aturan pembantu bertindak sebagai blok bangunan yang dapat digunakan kembali yang membuat kebijakan Anda lebih mudah dibaca dan dipelihara.
Aturan pembantu hanyalah kondisi bernama yang dievaluasi menjadi true ketika bodynya cocok. Anda kemudian dapat merujuk aturan ini dalam aturan deny atau denyGasSponsor Anda, termasuk dengan operator not untuk menegasikannya.
Contoh
# Tentukan aturan pembantu untuk memeriksa apakah permintaan dari sumber terpercaya
is_trusted if {
input.source_country in {"US", "GB", "DE"}
input.source_ip in {"203.0.113.10", "203.0.113.11"}
}
# Tentukan aturan lain untuk transaksi berisiko tinggi
is_high_risk if {
input.usd_value > 10000
}
is_high_risk if {
input.source_country in {"RU", "CN"}
}
# Gunakan aturan pembantu dalam kondisi deny
deny if {
not is_trusted
is_high_risk
}Aturan pembantu sangat berguna untuk:
- Penggunaan kembali: Tentukan kondisi sekali, gunakan dalam beberapa aturan
- Keterbacaan: Berikan nama yang bermakna pada kondisi kompleks
- Negasi: Gunakan
notuntuk memeriksa kapan kondisi TIDAK terpenuhi - Organisasi: Pecah kebijakan kompleks menjadi komponen logis
Operasi String
String adalah urutan karakter yang diapit tanda kutip ganda (""). Sebagian besar field input seperti input.chain, input.rpc_method, dan alamat adalah string. Rego menyediakan beberapa fungsi built-in untuk bekerja dengan string, penting untuk pencocokan pola pada alamat, nama metode, dan field teks lainnya.
| Fungsi | Deskripsi | Mengembalikan |
|---|---|---|
contains(string, substring) | Periksa apakah string berisi substring | boolean |
startswith(string, prefix) | Periksa apakah string dimulai dengan prefix | boolean |
endswith(string, suffix) | Periksa apakah string diakhiri dengan suffix | boolean |
lower(string) | Konversi ke huruf kecil | string |
upper(string) | Konversi ke huruf besar | string |
substring(string, start, length) | Ekstrak bagian dari string | string |
sprintf(format, values) | Format string dengan nilai | string |
Contoh
# Blokir metode apa pun yang mengandung "sign" (mencakup eth_sign, personal_sign, dll.)
deny if {
contains(input.rpc_method, "sign")
}
# Blokir alamat yang dimulai dengan prefix berbahaya yang diketahui
deny if {
startswith(lower(input.to_address), "0x000000000000000000000000000000000000dead")
}
# Blokir metode debug dan admin
deny if {
startswith(input.rpc_method, "debug_")
}
deny if {
startswith(input.rpc_method, "admin_")
}Operasi Array
Array adalah daftar nilai yang terurut, didefinisikan dengan kurung siku []. Tidak seperti set, array mempertahankan urutan elemen dan dapat berisi duplikat. Anda akan sering bekerja dengan array dalam kebijakan, terutama input.contract_addresses yang berisi semua alamat kontrak yang terlibat dalam permintaan.
# Sintaks array
my_array := ["first", "second", "third"]Rego menyediakan beberapa cara untuk memeriksa dan bekerja dengan array.
| Fungsi | Deskripsi | Mengembalikan |
|---|---|---|
count(array) | Jumlah elemen | number |
array[index] | Akses elemen berdasarkan indeks (berbasis 0) | element |
value in array | Periksa apakah nilai ada dalam array | boolean |
Contoh
# Batasi jumlah kontrak dalam satu permintaan
deny if {
count(input.contract_addresses) > 10
}
# Periksa apakah alamat tertentu ada dalam daftar kontrak
deny if {
"0xbanned..." in input.contract_addresses
}
# Akses elemen array tertentu
deny if {
count(input.contract_addresses) > 0
first_contract := input.contract_addresses[0]
startswith(first_contract, "0xdead")
}Pengujian Keanggotaan
Pengujian keanggotaan adalah salah satu operasi paling umum dalam kebijakan. Anda akan menggunakannya untuk memeriksa apakah nilai termasuk dalam allowlist, blocklist, atau koleksi nilai yang diizinkan lainnya.
Set
Set adalah koleksi nilai unik yang tidak terurut, didefinisikan dengan kurung kurawal {}. Gunakan operator in untuk menguji apakah nilai ada dalam set.
# Sintaks set
my_set := {"value1", "value2", "value3"}Set dioptimalkan untuk pengujian keanggotaan yang cepat, menjadikannya ideal untuk allowlist dan blocklist.
Contoh
# Blokir permintaan dari negara yang dikenai sanksi
blocked_countries := {"KP", "IR", "CU", "SY", "RU"}
deny if {
input.source_country in blocked_countries
}
# Hanya izinkan rantai tertentu
allowed_chains := {"polygon", "base", "arbitrum"}
deny if {
not input.chain in allowed_chains
}Set Inline vs Named
Anda dapat menentukan set inline dalam aturan atau sebagai variabel bernama di tingkat kebijakan. Set bernama meningkatkan keterbacaan dan memungkinkan penggunaan kembali di beberapa aturan.
Contoh
# Set inline - bagus untuk pemeriksaan sederhana sekali pakai
deny if {
input.rpc_method in {"eth_sign", "personal_sign", "eth_signTypedData"}
}
# Set bernama - lebih baik untuk penggunaan kembali dan keterbacaan
approved_contracts := {
"0xdac17f958d2ee523a2206206994597c13d831ec7", # USDT
"0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48", # USDC
"0x6b175474e89094c44da98b954eedeac495271d0f" # DAI
}
deny if {
some addr in input.contract_addresses
not addr in approved_contracts
}Iterasi dengan some
Kata kunci some memungkinkan Anda mengiterasi koleksi dan memeriksa kondisi terhadap setiap elemen. Ini penting saat bekerja dengan array seperti input.contract_addresses.
Iterasi Dasar
Gunakan some untuk memeriksa apakah ADA elemen dalam koleksi yang cocok dengan kondisi.
Contoh
# Tolak jika ADA alamat kontrak ada dalam blocklist
blocked_contracts := {"0xbanned1...", "0xbanned2..."}
deny if {
some addr in input.contract_addresses
addr in blocked_contracts
}Iterasi dengan Indeks
Anda juga dapat mengakses indeks setiap elemen selama iterasi.
Contoh
# Periksa kondisi pada posisi tertentu
deny if {
some i, addr in input.contract_addresses
i == 0 # Hanya kontrak pertama
startswith(addr, "0x000")
}Contoh: Menemukan Kecocokan Apa Pun
# Tolak jika kontrak apa pun dimulai dengan prefix yang mencurigakan
deny if {
some addr in input.contract_addresses
startswith(lower(addr), "0x000000000000000000000000")
}
# Tolak jika kontrak apa pun tidak ada dalam daftar yang disetujui
approved := {"0xusdt...", "0xusdc...", "0xdai..."}
deny if {
some addr in input.contract_addresses
not addr in approved
}Iterasi dengan every
Sementara some memeriksa apakah ADA elemen yang cocok, every memerlukan bahwa SEMUA elemen cocok dengan kondisi. Ini berguna untuk memastikan seluruh koleksi memenuhi kriteria Anda.
Contoh
# Tolak hanya jika SEMUA kontrak dari set yang mencurigakan
# (tidak mungkin sah jika setiap alamat mencurigakan)
suspicious_prefixes := {"0x0000000000000000"}
deny if {
count(input.contract_addresses) > 0
every addr in input.contract_addresses {
some prefix in suspicious_prefixes
startswith(addr, prefix)
}
}Contoh: Pola Validasi
# Pastikan semua kontrak dari daftar yang disetujui (kebalikan dari some/not)
approved_contracts := {"0xusdt...", "0xusdc...", "0xdai..."}
# Ini menolak jika ADA kontrak tidak disetujui
deny if {
some addr in input.contract_addresses
not addr in approved_contracts
}
# Setara menggunakan every (tolak jika TIDAK setiap kontrak disetujui)
deny if {
count(input.contract_addresses) > 0
not every addr in input.contract_addresses {
addr in approved_contracts
}
}Comprehension
Comprehension memungkinkan Anda membuat koleksi baru dengan mengubah atau memfilter yang sudah ada. Mereka berguna untuk mengekstrak nilai tertentu atau membangun dataset turunan.
Array Comprehension
Buat array baru dari elemen yang cocok dengan kriteria tertentu.
Contoh
# Ekstrak semua alamat kontrak yang dimulai dengan prefix tertentu
matching_contracts := [addr |
some addr in input.contract_addresses
startswith(addr, "0xa")
]
deny if {
count(matching_contracts) > 3
}Set Comprehension
Buat set nilai unik.
Contoh
# Dapatkan prefix unik dari semua alamat kontrak
contract_prefixes := {substring(addr, 0, 6) |
some addr in input.contract_addresses
}
# Tolak jika ada terlalu banyak prefix kontrak yang berbeda (mencurigakan)
deny if {
count(contract_prefixes) > 5
}Conditional Else
Kata kunci else memungkinkan Anda menentukan nilai fallback ketika kondisi tidak terpenuhi. Ini berguna untuk menghitung nilai turunan yang bervariasi berdasarkan input.
Contoh
# Tetapkan tingkat risiko berdasarkan nilai transaksi
risk_level := "critical" if {
input.usd_value > 100000
} else := "high" if {
input.usd_value > 10000
} else := "medium" if {
input.usd_value > 1000
} else := "low"
# Gunakan tingkat risiko yang dihitung dalam aturan deny
deny if {
risk_level == "critical"
}
denyGasSponsor if {
risk_level in {"high", "critical"}
}Contoh: Ambang Batas Spesifik Rantai
# Batas berbeda untuk rantai berbeda
chain_limit := 1000 if {
input.chain == "ethereum"
} else := 5000 if {
input.chain == "polygon"
} else := 10000
deny if {
input.usd_value > chain_limit
}