Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MemoryBuffer, precompiles, raw_call #885

Merged
merged 1 commit into from
May 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,17 @@ error: struct OutOfReachMarker is private
│ ^^^^^^^^^^^^^^^^ OutOfReachMarker

error: the struct `OutOfReachMarker` is private
┌─ compile_errors/emittable_not_implementable.fe:6:24
6 │ fn emit(self, _ val: OutOfReachMarker) {
│ ^^^^^^^^^^^^^^^^ this struct is not `pub`
┌─ src/context.fe:8:8
8 │ struct OutOfReachMarker {}
│ ---------------- `OutOfReachMarker` is defined here
= `OutOfReachMarker` can only be used within `context`
= Hint: use `pub` to make `OutOfReachMarker` visible from outside of `context`
┌─ compile_errors/emittable_not_implementable.fe:6:24
6 │ fn emit(self, _ val: OutOfReachMarker) {
│ ^^^^^^^^^^^^^^^^ this struct is not `pub`
┌─ src/context.fe:13:8
13 │ struct OutOfReachMarker {}
│ ---------------- `OutOfReachMarker` is defined here
= `OutOfReachMarker` can only be used within `context`
= Hint: use `pub` to make `OutOfReachMarker` visible from outside of `context`


308 changes: 308 additions & 0 deletions crates/library/std/src/buf.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,308 @@
use ingot::evm
use ingot::math

unsafe fn avail() -> u256 {
g-r-a-n-t marked this conversation as resolved.
Show resolved Hide resolved
let ptr: u256 = evm::mload(offset: 64)

if ptr == 0x00 {
return 96
} else {
return ptr
}
}

unsafe fn alloc(len: u256) -> u256 {
let ptr: u256 = avail()
evm::mstore(offset: 64, value: ptr + len)
return ptr
}

struct Cursor {
g-r-a-n-t marked this conversation as resolved.
Show resolved Hide resolved
cur: u256
len: u256

pub fn new(len: u256) -> Self {
return Cursor(cur: 0, len)
}

/// Increment the value of `cur` by `len` and return the value of `cur` before being incremented.
/// Reverts if the cursor is advanced beyond the given length.
pub fn advance(mut self, len: u256) -> u256 {
let cur: u256 = self.cur
assert cur + len < self.len + 1
self.cur += len
return cur
}

/// Length of the cursor remaining.
pub fn remainder(self) -> u256 {
return self.len - self.cur
}
}

/// EVM memory buffer abstraction.
pub struct MemoryBuffer {
offset: u256
len: u256

pub fn new(len: u256) -> Self {
unsafe {
return MemoryBuffer(offset: alloc(len), len)
}
}

pub fn from_u8(value: u8) -> Self {
let mut buf: MemoryBuffer = MemoryBuffer::new(len: 1)
let mut writer: MemoryBufferWriter = buf.writer()
writer.write_u8(value)
return buf
}

/// Length of the buffer in bytes.
pub fn len(self) -> u256 {
return self.len
}

/// The start of the buffer in EVM memory.
pub fn offset(self) -> u256 {
return self.offset
}

/// Returns a new buffer reader.
pub fn reader(self) -> MemoryBufferReader {
return MemoryBufferReader::new(buf: self)
}

/// Returns a new buffer writer.
pub fn writer(mut self) -> MemoryBufferWriter {
return MemoryBufferWriter::new(buf: self)
}
}

/// Memory buffer writer abstraction.
pub struct MemoryBufferWriter {
buf: MemoryBuffer
cur: Cursor

/// Returns a new writer for the given buffer.
pub fn new(mut buf: MemoryBuffer) -> Self {
return MemoryBufferWriter(
buf,
cur: Cursor::new(len: buf.len())
)
}

/// The number of bytes remaining to be written.
pub fn remainder(self) -> u256 {
return self.cur.remainder()
}

fn write_offset(mut self, len: u256) -> u256 {
return self.buf.offset() + self.cur.advance(len)
}

fn write_n(mut self, value: u256, len: u256) {
let offset: u256 = self.write_offset(len)
unsafe { rewrite_slot(offset, value, len) }
}

pub fn write_u8(mut self, value: u8) {
let offset: u256 = self.write_offset(len: 1)
unsafe { evm::mstore8(offset, value) }
}

pub fn write_u16(mut self, value: u16) {
self.write_n(value: u256(value), len: 2)
}

pub fn write_u32(mut self, value: u32) {
self.write_n(value: u256(value), len: 4)
}

pub fn write_u64(mut self, value: u64) {
self.write_n(value: u256(value), len: 8)
}

pub fn write_u128(mut self, value: u128) {
self.write_n(value: u256(value), len: 16)
}

pub fn write_u256(mut self, value: u256) {
let offset: u256 = self.write_offset(len: 32)
unsafe { evm::mstore(offset, value) }
}

pub fn write_buf(mut self, buf: MemoryBuffer) {
let mut reader: MemoryBufferReader = buf.reader()

while true {
let bytes_remaining: u256 = reader.remainder()

if bytes_remaining >= 32 {
self.write_u256(value: reader.read_u256())
} else if bytes_remaining == 0 {
break
} else {
self.write_u8(value: reader.read_u8())
}
}
}

// panicked at 'missing impl', crates/mir/src/lower/function.rs:1036:22
g-r-a-n-t marked this conversation as resolved.
Show resolved Hide resolved
// pub fn write<T: MemoryBufferWrite>(mut self, value: T) {
// value.write_buf(writer: self)
// }
}

// pub trait MemoryBufferWrite {
// fn write_buf(self, mut writer: MemoryBufferWriter);
// }
//
// impl MemoryBufferWrite for u256 { .. }
// .
// .
// impl MemoryBufferWrite for u8 { .. }

/// Rewrites the left-most `len` bytes in slot with the right-most `len` bytes of `value`.
unsafe fn rewrite_slot(offset: u256, value: u256, len: u256) {
// bit mask for right side of 256 bit slot
let mask: u256 = evm::shr(
bits: len * 8,
value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
)
// new value shifted to left
let shifted_value: u256 = evm::shl(
bits: 256 - len * 8,
value
)

let old_value: u256 = evm::mload(offset)
let new_value: u256 = evm::bitwise_or(
evm::bitwise_and(mask, old_value),
shifted_value
)
evm::mstore(offset, value: new_value)
}

/// Memory buffer reader abstraction.
pub struct MemoryBufferReader {
buf: MemoryBuffer
cur: Cursor

/// Returns a new reader for the given buffer.
pub fn new(buf: MemoryBuffer) -> Self {
return MemoryBufferReader(buf, cur: Cursor::new(len: buf.len()))
}

/// The number of bytes remaining to be read.
pub fn remainder(self) -> u256 {
return self.cur.remainder()
}

fn read_offset(mut self, len: u256) -> u256 {
return self.buf.offset() + self.cur.advance(len)
}

fn read_n(mut self, len: u256) -> u256 {
let offset: u256 = self.read_offset(len)
unsafe {
let value: u256 = evm::mload(offset)
return evm::shr(bits: 256 - len * 8, value)
}
}

pub fn read_u8(mut self) -> u8 {
return u8(self.read_n(len: 1))
}

pub fn read_u16(mut self) -> u16 {
return u16(self.read_n(len: 2))
}

pub fn read_u32(mut self) -> u32 {
return u32(self.read_n(len: 4))
}

pub fn read_u64(mut self) -> u64 {
return u64(self.read_n(len: 8))
}

pub fn read_u128(mut self) -> u128 {
return u128(self.read_n(len: 16))
}

pub fn read_u256(mut self) -> u256 {
let offset: u256 = self.read_offset(len: 32)
unsafe {
let value: u256 = evm::mload(offset)
return value
}
}

pub fn read_buf(mut self, len: u256) -> MemoryBuffer {
let mut buf: MemoryBuffer = MemoryBuffer::new(len)
let mut writer: MemoryBufferWriter = buf.writer()

while true {
let bytes_remaining: u256 = writer.remainder()

if bytes_remaining >= 32 {
writer.write_u256(value: self.read_u256())
} else if bytes_remaining == 0 {
break
} else {
writer.write_u8(value: self.read_u8())
}
}

return buf
}

// `T` has not been defined
g-r-a-n-t marked this conversation as resolved.
Show resolved Hide resolved
// pub fn read<T: MemoryBufferRead>(mut self) -> T {
// T::read_buf(writer: self)
// }
}

// pub trait MemoryBufferRead {
// fn read_buf(self, mut reader: MemoryBufferReader) -> Self;
// }
//
// impl MemoryBufferRead for u256 { .. }
// .
// .
// impl MemoryBufferRead for u8 { .. }

/// `MemoryBuffer` wrapper for raw calls to other contracts.
pub struct RawCallBuffer {
input_len: u256
output_len: u256
buf: MemoryBuffer

pub fn new(input_len: u256, output_len: u256) -> Self {
let len: u256 = math::max(input_len, output_len)
let buf: MemoryBuffer = MemoryBuffer::new(len)

return RawCallBuffer(input_len, output_len, buf)
}

pub fn input_len(self) -> u256 {
return self.input_len
}

pub fn output_len(self) -> u256 {
return self.output_len
}

pub fn offset(self) -> u256 {
return self.buf.offset()
}

pub fn reader(self) -> MemoryBufferReader {
return self.buf.reader()
}

pub fn writer(mut self) -> MemoryBufferWriter {
return self.buf.writer()
}
}
29 changes: 27 additions & 2 deletions crates/library/std/src/context.fe
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ use ingot::error::{
ERROR_FAILED_SEND_VALUE,
Error
}
use ingot::buf::{
RawCallBuffer,
MemoryBufferReader,
MemoryBufferWriter
}

struct OutOfReachMarker {}

Expand Down Expand Up @@ -56,7 +61,7 @@ pub struct Context {
}

pub fn msg_sig(self) -> u256 {
unsafe { return evm::shr(224, evm::call_data_load(offset: 0)) }
unsafe { return evm::shr(bits: 224, value: evm::call_data_load(offset: 0)) }
}

pub fn balance_of(self, _ account: address) -> u256 {
Expand Down Expand Up @@ -86,7 +91,27 @@ pub struct Context {
}
}

/// Makes a call to the given address.
pub fn raw_call(
self,
addr: address,
value: u256,
mut buf: RawCallBuffer
) -> bool {
unsafe {
return evm::call(
gas: evm::gas_remaining(),
addr,
value,
input_offset: buf.offset(),
input_len: buf.input_len(),
output_offset: buf.offset(),
output_len: buf.output_len()
) == 1
}
}

pub fn emit<T: Emittable>(mut self, _ val: T) {
val.emit(OutOfReachMarker())
}
}
}
Loading