Skip to main content

thalir_core/
metadata.rs

1use crate::block::BlockId;
2use crate::values::Value;
3use num_bigint::BigUint;
4use serde::{Deserialize, Serialize};
5use std::collections::{HashMap, HashSet};
6
7#[derive(Debug, Clone, Default, Serialize, Deserialize)]
8pub struct SecurityMetadata {
9    pub external_calls: Vec<ExternalCallSite>,
10    pub state_mutations: Vec<StateMutation>,
11    pub reentrancy_guards: Vec<ReentrancyGuard>,
12    pub access_controls: Vec<AccessControl>,
13    pub checked_operations: Vec<CheckedOp>,
14    pub vulnerability_patterns: Vec<VulnerabilityPattern>,
15}
16
17#[derive(Debug, Clone, Serialize, Deserialize)]
18pub struct ExternalCallSite {
19    pub location: InstructionLocation,
20    pub target: CallTarget,
21    pub value_transfer: bool,
22    pub state_changes_before: Vec<StateChange>,
23    pub state_changes_after: Vec<StateChange>,
24    pub can_reenter: bool,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
28pub struct InstructionLocation {
29    pub block: BlockId,
30    pub index: usize,
31}
32
33#[derive(Debug, Clone, Serialize, Deserialize)]
34pub enum CallTarget {
35    Known(String),
36    Unknown,
37    UserControlled,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct StateChange {
42    pub storage_key: StorageKeyInfo,
43    pub change_type: StateChangeType,
44}
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
47pub enum StorageKeyInfo {
48    Slot(BigUint),
49    Mapping { base: BigUint, key: String },
50    Dynamic(String),
51}
52
53#[derive(Debug, Clone, Serialize, Deserialize)]
54pub enum StateChangeType {
55    Write,
56    Delete,
57    Increment,
58    Decrement,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct StateMutation {
63    pub location: InstructionLocation,
64    pub mutated_var: String,
65    pub mutation_type: MutationType,
66    pub depends_on_input: bool,
67}
68
69#[derive(Debug, Clone, Serialize, Deserialize)]
70pub enum MutationType {
71    Assignment,
72    Arithmetic,
73    ArrayPush,
74    ArrayPop,
75    MappingUpdate,
76    Deletion,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize)]
80pub struct ReentrancyGuard {
81    pub guard_type: ReentrancyGuardType,
82    pub protected_blocks: Vec<BlockId>,
83    pub guard_variable: Option<String>,
84}
85
86#[derive(Debug, Clone, Serialize, Deserialize)]
87pub enum ReentrancyGuardType {
88    Mutex,
89    CheckEffectsInteraction,
90    NonReentrantModifier,
91}
92
93#[derive(Debug, Clone, Serialize, Deserialize)]
94pub struct AccessControl {
95    pub control_type: AccessControlType,
96    pub location: InstructionLocation,
97    pub condition: AccessCondition,
98}
99
100#[derive(Debug, Clone, Serialize, Deserialize)]
101pub enum AccessControlType {
102    OwnerOnly,
103    RoleBased(String),
104    Whitelist,
105    Pausable,
106    Custom,
107}
108
109#[derive(Debug, Clone, Serialize, Deserialize)]
110pub enum AccessCondition {
111    RequireStatement,
112    Modifier(String),
113    IfStatement,
114}
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct CheckedOp {
118    pub location: InstructionLocation,
119    pub operation: CheckedOperation,
120    pub overflow_behavior: OverflowBehavior,
121}
122
123#[derive(Debug, Clone, Serialize, Deserialize)]
124pub enum CheckedOperation {
125    Addition,
126    Subtraction,
127    Multiplication,
128    Division,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
132pub enum OverflowBehavior {
133    Revert,
134    Wrap,
135    Saturate,
136}
137
138#[derive(Debug, Clone, Serialize, Deserialize)]
139pub enum VulnerabilityPattern {
140    Reentrancy {
141        call_site: InstructionLocation,
142        state_changes: Vec<StateChange>,
143    },
144    IntegerOverflow {
145        location: InstructionLocation,
146        operation: String,
147    },
148    UnprotectedTransfer {
149        location: InstructionLocation,
150        recipient: String,
151    },
152    AccessControl {
153        function: String,
154        missing_check: String,
155    },
156    TimestampDependence {
157        location: InstructionLocation,
158        usage: String,
159    },
160    UncheckedReturn {
161        call_location: InstructionLocation,
162        ignored_value: String,
163    },
164}
165
166#[derive(Debug, Clone, Default, Serialize, Deserialize)]
167pub struct OptimizationHints {
168    pub pure_functions: HashSet<String>,
169    pub view_functions: HashSet<String>,
170    pub constant_expressions: Vec<ConstantExpression>,
171    pub loop_bounds: HashMap<BlockId, LoopBound>,
172    pub invariants: Vec<Invariant>,
173}
174
175#[derive(Debug, Clone, Serialize, Deserialize)]
176pub struct ConstantExpression {
177    pub location: InstructionLocation,
178    pub value: Value,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct LoopBound {
183    pub min_iterations: Option<u64>,
184    pub max_iterations: Option<u64>,
185    pub bound_expression: Option<String>,
186}
187
188#[derive(Debug, Clone, Serialize, Deserialize)]
189pub struct Invariant {
190    pub condition: String,
191    pub scope: InvariantScope,
192}
193
194#[derive(Debug, Clone, Serialize, Deserialize)]
195pub enum InvariantScope {
196    Function(String),
197    Loop(BlockId),
198    Contract,
199}
200
201#[derive(Debug, Clone, Default, Serialize, Deserialize)]
202pub struct AnalysisMetadata {
203    pub data_dependencies: DataDependencies,
204    pub control_dependencies: ControlDependencies,
205    pub taint_analysis: TaintAnalysis,
206}
207
208#[derive(Debug, Clone, Default, Serialize, Deserialize)]
209pub struct DataDependencies {
210    pub def_use_chains: HashMap<Value, HashSet<InstructionLocation>>,
211    pub use_def_chains: HashMap<InstructionLocation, HashSet<Value>>,
212}
213
214#[derive(Debug, Clone, Default, Serialize, Deserialize)]
215pub struct ControlDependencies {
216    pub dominators: HashMap<BlockId, HashSet<BlockId>>,
217    pub post_dominators: HashMap<BlockId, HashSet<BlockId>>,
218}
219
220#[derive(Debug, Clone, Default, Serialize, Deserialize)]
221pub struct TaintAnalysis {
222    pub tainted_values: HashSet<Value>,
223    pub taint_sources: Vec<TaintSource>,
224    pub taint_sinks: Vec<TaintSink>,
225}
226
227#[derive(Debug, Clone, Serialize, Deserialize)]
228pub struct TaintSource {
229    pub source_type: TaintSourceType,
230    pub location: InstructionLocation,
231    pub value: Value,
232}
233
234#[derive(Debug, Clone, Serialize, Deserialize)]
235pub enum TaintSourceType {
236    UserInput,
237    ExternalCall,
238    Storage,
239    Timestamp,
240}
241
242#[derive(Debug, Clone, Serialize, Deserialize)]
243pub struct TaintSink {
244    pub sink_type: TaintSinkType,
245    pub location: InstructionLocation,
246    pub value: Value,
247}
248
249#[derive(Debug, Clone, Serialize, Deserialize)]
250pub enum TaintSinkType {
251    StateChange,
252    ExternalCall,
253    Transfer,
254    Selfdestruct,
255}
256
257impl SecurityMetadata {
258    pub fn has_high_risk_patterns(&self) -> bool {
259        for call in &self.external_calls {
260            if call.value_transfer && !call.state_changes_after.is_empty() {
261                return true;
262            }
263        }
264
265        for mutation in &self.state_mutations {
266            if mutation.depends_on_input && self.access_controls.is_empty() {
267                return true;
268            }
269        }
270
271        false
272    }
273
274    pub fn state_modifying_functions(&self) -> HashSet<String> {
275        let functions = HashSet::new();
276
277        for _mutation in &self.state_mutations {}
278
279        functions
280    }
281}