Skip to content

Commit 797586f

Browse files
authored
Merge pull request #885 from g-r-a-n-t/precompiles
MemoryBuffer, precompiles, raw_call
2 parents e16f122 + bd18a94 commit 797586f

File tree

13 files changed

+898
-29
lines changed

13 files changed

+898
-29
lines changed

crates/analyzer/tests/snapshots/errors__emittable_not_implementable.snap

+12-12
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,17 @@ error: struct OutOfReachMarker is private
99
^^^^^^^^^^^^^^^^ OutOfReachMarker
1010

1111
error: the struct `OutOfReachMarker` is private
12-
┌─ compile_errors/emittable_not_implementable.fe:6:24
13-
14-
6fn emit(self, _ val: OutOfReachMarker) {
15-
^^^^^^^^^^^^^^^^ this struct is not `pub`
16-
17-
┌─ src/context.fe:8:8
18-
19-
8struct OutOfReachMarker {}
20-
---------------- `OutOfReachMarker` is defined here
21-
22-
= `OutOfReachMarker` can only be used within `context`
23-
= Hint: use `pub` to make `OutOfReachMarker` visible from outside of `context`
12+
┌─ compile_errors/emittable_not_implementable.fe:6:24
13+
14+
6fn emit(self, _ val: OutOfReachMarker) {
15+
^^^^^^^^^^^^^^^^ this struct is not `pub`
16+
17+
┌─ src/context.fe:13:8
18+
19+
13struct OutOfReachMarker {}
20+
---------------- `OutOfReachMarker` is defined here
21+
22+
= `OutOfReachMarker` can only be used within `context`
23+
= Hint: use `pub` to make `OutOfReachMarker` visible from outside of `context`
2424

2525

crates/library/std/src/buf.fe

+308
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,308 @@
1+
use ingot::evm
2+
use ingot::math
3+
4+
unsafe fn avail() -> u256 {
5+
let ptr: u256 = evm::mload(offset: 64)
6+
7+
if ptr == 0x00 {
8+
return 96
9+
} else {
10+
return ptr
11+
}
12+
}
13+
14+
unsafe fn alloc(len: u256) -> u256 {
15+
let ptr: u256 = avail()
16+
evm::mstore(offset: 64, value: ptr + len)
17+
return ptr
18+
}
19+
20+
struct Cursor {
21+
cur: u256
22+
len: u256
23+
24+
pub fn new(len: u256) -> Self {
25+
return Cursor(cur: 0, len)
26+
}
27+
28+
/// Increment the value of `cur` by `len` and return the value of `cur` before being incremented.
29+
/// Reverts if the cursor is advanced beyond the given length.
30+
pub fn advance(mut self, len: u256) -> u256 {
31+
let cur: u256 = self.cur
32+
assert cur + len < self.len + 1
33+
self.cur += len
34+
return cur
35+
}
36+
37+
/// Length of the cursor remaining.
38+
pub fn remainder(self) -> u256 {
39+
return self.len - self.cur
40+
}
41+
}
42+
43+
/// EVM memory buffer abstraction.
44+
pub struct MemoryBuffer {
45+
offset: u256
46+
len: u256
47+
48+
pub fn new(len: u256) -> Self {
49+
unsafe {
50+
return MemoryBuffer(offset: alloc(len), len)
51+
}
52+
}
53+
54+
pub fn from_u8(value: u8) -> Self {
55+
let mut buf: MemoryBuffer = MemoryBuffer::new(len: 1)
56+
let mut writer: MemoryBufferWriter = buf.writer()
57+
writer.write_u8(value)
58+
return buf
59+
}
60+
61+
/// Length of the buffer in bytes.
62+
pub fn len(self) -> u256 {
63+
return self.len
64+
}
65+
66+
/// The start of the buffer in EVM memory.
67+
pub fn offset(self) -> u256 {
68+
return self.offset
69+
}
70+
71+
/// Returns a new buffer reader.
72+
pub fn reader(self) -> MemoryBufferReader {
73+
return MemoryBufferReader::new(buf: self)
74+
}
75+
76+
/// Returns a new buffer writer.
77+
pub fn writer(mut self) -> MemoryBufferWriter {
78+
return MemoryBufferWriter::new(buf: self)
79+
}
80+
}
81+
82+
/// Memory buffer writer abstraction.
83+
pub struct MemoryBufferWriter {
84+
buf: MemoryBuffer
85+
cur: Cursor
86+
87+
/// Returns a new writer for the given buffer.
88+
pub fn new(mut buf: MemoryBuffer) -> Self {
89+
return MemoryBufferWriter(
90+
buf,
91+
cur: Cursor::new(len: buf.len())
92+
)
93+
}
94+
95+
/// The number of bytes remaining to be written.
96+
pub fn remainder(self) -> u256 {
97+
return self.cur.remainder()
98+
}
99+
100+
fn write_offset(mut self, len: u256) -> u256 {
101+
return self.buf.offset() + self.cur.advance(len)
102+
}
103+
104+
fn write_n(mut self, value: u256, len: u256) {
105+
let offset: u256 = self.write_offset(len)
106+
unsafe { rewrite_slot(offset, value, len) }
107+
}
108+
109+
pub fn write_u8(mut self, value: u8) {
110+
let offset: u256 = self.write_offset(len: 1)
111+
unsafe { evm::mstore8(offset, value) }
112+
}
113+
114+
pub fn write_u16(mut self, value: u16) {
115+
self.write_n(value: u256(value), len: 2)
116+
}
117+
118+
pub fn write_u32(mut self, value: u32) {
119+
self.write_n(value: u256(value), len: 4)
120+
}
121+
122+
pub fn write_u64(mut self, value: u64) {
123+
self.write_n(value: u256(value), len: 8)
124+
}
125+
126+
pub fn write_u128(mut self, value: u128) {
127+
self.write_n(value: u256(value), len: 16)
128+
}
129+
130+
pub fn write_u256(mut self, value: u256) {
131+
let offset: u256 = self.write_offset(len: 32)
132+
unsafe { evm::mstore(offset, value) }
133+
}
134+
135+
pub fn write_buf(mut self, buf: MemoryBuffer) {
136+
let mut reader: MemoryBufferReader = buf.reader()
137+
138+
while true {
139+
let bytes_remaining: u256 = reader.remainder()
140+
141+
if bytes_remaining >= 32 {
142+
self.write_u256(value: reader.read_u256())
143+
} else if bytes_remaining == 0 {
144+
break
145+
} else {
146+
self.write_u8(value: reader.read_u8())
147+
}
148+
}
149+
}
150+
151+
// panicked at 'missing impl', crates/mir/src/lower/function.rs:1036:22
152+
// pub fn write<T: MemoryBufferWrite>(mut self, value: T) {
153+
// value.write_buf(writer: self)
154+
// }
155+
}
156+
157+
// pub trait MemoryBufferWrite {
158+
// fn write_buf(self, mut writer: MemoryBufferWriter);
159+
// }
160+
//
161+
// impl MemoryBufferWrite for u256 { .. }
162+
// .
163+
// .
164+
// impl MemoryBufferWrite for u8 { .. }
165+
166+
/// Rewrites the left-most `len` bytes in slot with the right-most `len` bytes of `value`.
167+
unsafe fn rewrite_slot(offset: u256, value: u256, len: u256) {
168+
// bit mask for right side of 256 bit slot
169+
let mask: u256 = evm::shr(
170+
bits: len * 8,
171+
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
172+
)
173+
// new value shifted to left
174+
let shifted_value: u256 = evm::shl(
175+
bits: 256 - len * 8,
176+
value
177+
)
178+
179+
let old_value: u256 = evm::mload(offset)
180+
let new_value: u256 = evm::bitwise_or(
181+
evm::bitwise_and(mask, old_value),
182+
shifted_value
183+
)
184+
evm::mstore(offset, value: new_value)
185+
}
186+
187+
/// Memory buffer reader abstraction.
188+
pub struct MemoryBufferReader {
189+
buf: MemoryBuffer
190+
cur: Cursor
191+
192+
/// Returns a new reader for the given buffer.
193+
pub fn new(buf: MemoryBuffer) -> Self {
194+
return MemoryBufferReader(buf, cur: Cursor::new(len: buf.len()))
195+
}
196+
197+
/// The number of bytes remaining to be read.
198+
pub fn remainder(self) -> u256 {
199+
return self.cur.remainder()
200+
}
201+
202+
fn read_offset(mut self, len: u256) -> u256 {
203+
return self.buf.offset() + self.cur.advance(len)
204+
}
205+
206+
fn read_n(mut self, len: u256) -> u256 {
207+
let offset: u256 = self.read_offset(len)
208+
unsafe {
209+
let value: u256 = evm::mload(offset)
210+
return evm::shr(bits: 256 - len * 8, value)
211+
}
212+
}
213+
214+
pub fn read_u8(mut self) -> u8 {
215+
return u8(self.read_n(len: 1))
216+
}
217+
218+
pub fn read_u16(mut self) -> u16 {
219+
return u16(self.read_n(len: 2))
220+
}
221+
222+
pub fn read_u32(mut self) -> u32 {
223+
return u32(self.read_n(len: 4))
224+
}
225+
226+
pub fn read_u64(mut self) -> u64 {
227+
return u64(self.read_n(len: 8))
228+
}
229+
230+
pub fn read_u128(mut self) -> u128 {
231+
return u128(self.read_n(len: 16))
232+
}
233+
234+
pub fn read_u256(mut self) -> u256 {
235+
let offset: u256 = self.read_offset(len: 32)
236+
unsafe {
237+
let value: u256 = evm::mload(offset)
238+
return value
239+
}
240+
}
241+
242+
pub fn read_buf(mut self, len: u256) -> MemoryBuffer {
243+
let mut buf: MemoryBuffer = MemoryBuffer::new(len)
244+
let mut writer: MemoryBufferWriter = buf.writer()
245+
246+
while true {
247+
let bytes_remaining: u256 = writer.remainder()
248+
249+
if bytes_remaining >= 32 {
250+
writer.write_u256(value: self.read_u256())
251+
} else if bytes_remaining == 0 {
252+
break
253+
} else {
254+
writer.write_u8(value: self.read_u8())
255+
}
256+
}
257+
258+
return buf
259+
}
260+
261+
// `T` has not been defined
262+
// pub fn read<T: MemoryBufferRead>(mut self) -> T {
263+
// T::read_buf(writer: self)
264+
// }
265+
}
266+
267+
// pub trait MemoryBufferRead {
268+
// fn read_buf(self, mut reader: MemoryBufferReader) -> Self;
269+
// }
270+
//
271+
// impl MemoryBufferRead for u256 { .. }
272+
// .
273+
// .
274+
// impl MemoryBufferRead for u8 { .. }
275+
276+
/// `MemoryBuffer` wrapper for raw calls to other contracts.
277+
pub struct RawCallBuffer {
278+
input_len: u256
279+
output_len: u256
280+
buf: MemoryBuffer
281+
282+
pub fn new(input_len: u256, output_len: u256) -> Self {
283+
let len: u256 = math::max(input_len, output_len)
284+
let buf: MemoryBuffer = MemoryBuffer::new(len)
285+
286+
return RawCallBuffer(input_len, output_len, buf)
287+
}
288+
289+
pub fn input_len(self) -> u256 {
290+
return self.input_len
291+
}
292+
293+
pub fn output_len(self) -> u256 {
294+
return self.output_len
295+
}
296+
297+
pub fn offset(self) -> u256 {
298+
return self.buf.offset()
299+
}
300+
301+
pub fn reader(self) -> MemoryBufferReader {
302+
return self.buf.reader()
303+
}
304+
305+
pub fn writer(mut self) -> MemoryBufferWriter {
306+
return self.buf.writer()
307+
}
308+
}

crates/library/std/src/context.fe

+27-2
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,11 @@ use ingot::error::{
44
ERROR_FAILED_SEND_VALUE,
55
Error
66
}
7+
use ingot::buf::{
8+
RawCallBuffer,
9+
MemoryBufferReader,
10+
MemoryBufferWriter
11+
}
712

813
struct OutOfReachMarker {}
914

@@ -56,7 +61,7 @@ pub struct Context {
5661
}
5762

5863
pub fn msg_sig(self) -> u256 {
59-
unsafe { return evm::shr(224, evm::call_data_load(offset: 0)) }
64+
unsafe { return evm::shr(bits: 224, value: evm::call_data_load(offset: 0)) }
6065
}
6166

6267
pub fn balance_of(self, _ account: address) -> u256 {
@@ -86,7 +91,27 @@ pub struct Context {
8691
}
8792
}
8893

94+
/// Makes a call to the given address.
95+
pub fn raw_call(
96+
self,
97+
addr: address,
98+
value: u256,
99+
mut buf: RawCallBuffer
100+
) -> bool {
101+
unsafe {
102+
return evm::call(
103+
gas: evm::gas_remaining(),
104+
addr,
105+
value,
106+
input_offset: buf.offset(),
107+
input_len: buf.input_len(),
108+
output_offset: buf.offset(),
109+
output_len: buf.output_len()
110+
) == 1
111+
}
112+
}
113+
89114
pub fn emit<T: Emittable>(mut self, _ val: T) {
90115
val.emit(OutOfReachMarker())
91-
}
116+
}
92117
}

0 commit comments

Comments
 (0)