forked from ethereum/fe
-
Notifications
You must be signed in to change notification settings - Fork 0
/
data.rs
179 lines (154 loc) · 5.81 KB
/
data.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
use crate::yul::operations::abi as abi_operations;
use fe_analyzer::namespace::events::Event;
use fe_analyzer::namespace::types::{
Array,
FeSized,
FixedSize,
};
use yultsur::*;
/// Loads a value of the given type from storage.
pub fn sload<T: FeSized>(typ: T, sptr: yul::Expression) -> yul::Expression {
let size = literal_expression! { (typ.size()) };
expression! { bytes_sloadn([sptr], [size]) }
}
/// Stores a value of the given type in storage.
pub fn sstore<T: FeSized>(typ: T, sptr: yul::Expression, value: yul::Expression) -> yul::Statement {
let size = literal_expression! { (typ.size()) };
statement! { bytes_sstoren([sptr], [size], [value]) }
}
/// Loads a value of the given type from memory.
pub fn mload<T: FeSized>(typ: T, mptr: yul::Expression) -> yul::Expression {
let size = literal_expression! { (typ.size()) };
expression! { mloadn([mptr], [size]) }
}
/// Stores a value of the given type in memory.
pub fn mstore<T: FeSized>(typ: T, mptr: yul::Expression, value: yul::Expression) -> yul::Statement {
let size = literal_expression! { (typ.size()) };
statement! { mstoren([mptr], [size], [value]) }
}
/// Copies a segment of memory into storage.
pub fn mcopys<T: FeSized>(typ: T, sptr: yul::Expression, mptr: yul::Expression) -> yul::Statement {
let size = literal_expression! { (typ.size()) };
let word_ptr = expression! { div([sptr], 32) };
statement! { mcopys([mptr], [word_ptr], [size]) }
}
/// Copies a segment of storage into memory.
///
/// Returns the address of the data in memory.
pub fn scopym<T: FeSized>(typ: T, sptr: yul::Expression) -> yul::Expression {
let size = literal_expression! { (typ.size()) };
let word_ptr = expression! { div([sptr], 32) };
expression! { scopym([word_ptr], [size]) }
}
/// Copies a segment of storage to another segment of storage.
pub fn scopys<T: FeSized>(
typ: T,
dest_ptr: yul::Expression,
origin_ptr: yul::Expression,
) -> yul::Statement {
let size = literal_expression! { (typ.size()) };
let origin_word = expression! { div([origin_ptr], 32) };
let dest_word = expression! { div([dest_ptr], 32) };
statement! { scopys([origin_word], [dest_word], [size]) }
}
/// Copies a segment of memory to another segment of memory.
pub fn mcopym<T: FeSized>(typ: T, ptr: yul::Expression) -> yul::Expression {
let size = literal_expression! { (typ.size()) };
expression! { mcopym([ptr], [size]) }
}
/// Logs an event.
pub fn emit_event(event: Event, vals: Vec<yul::Expression>) -> yul::Statement {
let mut topics = vec![literal_expression! { (event.topic) }];
let (field_vals, field_types): (Vec<yul::Expression>, Vec<FixedSize>) = event
.non_indexed_fields()
.into_iter()
.map(|(index, typ)| (vals[index].to_owned(), typ))
.unzip();
// field types will be relevant when we implement indexed array values
let (mut indexed_field_vals, _): (Vec<yul::Expression>, Vec<FixedSize>) = event
.indexed_fields()
.into_iter()
.map(|(index, typ)| (vals[index].to_owned(), typ))
.unzip();
let encoding = abi_operations::encode(field_types.clone(), field_vals);
let encoding_size = abi_operations::encode_size(field_types, vals);
// for now we assume these are all base type values and therefore do not need to
// be hashed
topics.append(&mut indexed_field_vals);
let log_func = identifier! { (format!("log{}", topics.len())) };
return statement! { [log_func]([encoding], [encoding_size], [topics...]) };
}
/// Sums a list of expressions using nested add operations.
pub fn sum(vals: Vec<yul::Expression>) -> yul::Expression {
if vals.is_empty() {
return expression! { 0 };
}
vals.into_iter()
.fold_first(|val1, val2| expression! { add([val1], [val2]) })
.unwrap()
}
/// Hashes the storage nonce of a map with a key to determine the value's
/// location in storage.
pub fn keyed_map(map: yul::Expression, key: yul::Expression) -> yul::Expression {
expression! { map_value_ptr([map], [key]) }
}
/// Finds the location of an array element base on the element size, element
/// index, and array location.
pub fn indexed_array(
typ: Array,
array: yul::Expression,
index: yul::Expression,
) -> yul::Expression {
let inner_size = literal_expression! { (typ.inner.size()) };
expression! { add([array], (mul([index], [inner_size]))) }
}
#[cfg(test)]
mod tests {
use crate::yul::operations::data::{
emit_event,
sum,
};
use fe_analyzer::namespace::events::Event;
use fe_analyzer::namespace::types::{
Base,
FixedSize,
U256,
};
use yultsur::*;
#[test]
fn test_emit_event_no_indexed() {
let event = Event::new(
"MyEvent",
vec![FixedSize::Base(U256), FixedSize::Base(Base::Address)],
vec![],
);
assert_eq!(
emit_event(event, vec![expression! { 26 }, expression! { 0x00 }]).to_string(),
"log1(abi_encode_uint256_address(26, 0x00), add(64, 0), 0x74bffa18f2b20140b65de9264a54040b23ab0a34e7643d52f67f7fb18be9bbcb)"
)
}
#[test]
fn test_emit_event_one_indexed() {
let event = Event::new(
"MyEvent",
vec![FixedSize::Base(U256), FixedSize::Base(Base::Address)],
vec![0],
);
assert_eq!(
emit_event(event, vec![expression! { 26 }, expression! { 0x00 }]).to_string(),
"log2(abi_encode_address(0x00), add(32, 0), 0x74bffa18f2b20140b65de9264a54040b23ab0a34e7643d52f67f7fb18be9bbcb, 26)"
)
}
#[test]
fn test_sum() {
assert_eq!(
sum(vec![
expression! { 42 },
expression! { 26 },
expression! { 22 }
])
.to_string(),
"add(add(42, 26), 22)"
)
}
}