Skip to content

Commit

Permalink
MemoryBuffer, precompiles, raw_call
Browse files Browse the repository at this point in the history
  • Loading branch information
g-r-a-n-t authored and Grant Wuerker committed May 17, 2023
1 parent e16f122 commit b2c4370
Show file tree
Hide file tree
Showing 11 changed files with 713 additions and 19 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ error: the struct `OutOfReachMarker` is private
6fn emit(self, _ val: OutOfReachMarker) {
^^^^^^^^^^^^^^^^ this struct is not `pub`
┌─ src/context.fe:8:8
┌─ src/context.fe:9:8
8struct OutOfReachMarker {}
9struct OutOfReachMarker {}
---------------- `OutOfReachMarker` is defined here
= `OutOfReachMarker` can only be used within `context`
Expand Down
281 changes: 281 additions & 0 deletions crates/library/std/src/buf.fe
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
use ingot::evm

unsafe fn avail() -> u256 {
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 {
cur: u256
len: u256

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

pub fn advance(mut self, len: u256) -> u256 {
let cur: u256 = self.cur
assert cur + len < self.len + 1
self.cur += len
return cur
}

pub fn remainder(self) -> u256 {
return self.len - self.cur
}
}

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
}

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

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

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

pub fn writer(mut self) -> MemoryBufferWriter {
return MemoryBufferWriter::new(buf: self)
}
}

pub struct MemoryBufferWriter {
buf: MemoryBuffer
cur: Cursor

pub fn new(mut buf: MemoryBuffer) -> Self {
return MemoryBufferWriter(
buf,
cur: Cursor::new(len: buf.len())
)
}

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())
}
}
}

// todo: fix compiler panic produced by this
// pub fn write<T: MemoryBufferWrite>(mut self, value: T) {
// self.cur += value.write_buf(writer: self)
// }
}

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)
}

pub struct MemoryBufferReader {
buf: MemoryBuffer
cur: Cursor

pub fn new(buf: MemoryBuffer) -> Self {
return MemoryBufferReader(buf, cur: Cursor::new(len: buf.len()))
}

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
}

// todo: fix compiler panic produced by this
// pub fn write<T: MemoryBufferWrite>(mut self, value: T) {
// self.cur += value.write_buf(writer: self)
// }
}


// pub struct MemoryBufferReader {
// buf: MemoryBuffer
// cur: u256

// pub fn buf(self) -> MemoryBuffer {
// return self.buf
// }

// // cannot be implemented generically due to error described below
// pub fn read(mut self) -> u256 {
// unsafe {
// let value: u256 = evm::mload(offset: self.buf().offset() + self.cur)
// self.cur += 32
// return value
// }
// }
// }

pub trait MemoryBufferWrite {
fn write_buf(self, mut writer: MemoryBufferWriter) -> u256;
}

// todo: fix `Self` is not defined according to compiler
// trait MemoryBufferRead {
// fn read_buf(mut buf: MemoryBufferReader) -> (Self, u256);
// }

// impl MemoryBufferWrite for u256 {
// fn write_buf(self, mut writer: MemoryBufferWriter) -> u256 {
// unsafe {
// evm::mstore(
// offset: writer.buf().offset() + writer.cur(),
// value: self
// )
// }

// return 32
// }
// }
19 changes: 17 additions & 2 deletions crates/library/std/src/context.fe
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use ingot::error::{
ERROR_FAILED_SEND_VALUE,
Error
}
use ingot::buf::MemoryBuffer

struct OutOfReachMarker {}

Expand Down Expand Up @@ -56,7 +57,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 +87,21 @@ pub struct Context {
}
}

pub fn raw_call(self, addr: address, value: u256, mut buf: MemoryBuffer) {
unsafe {
assert evm::call(
gas: evm::gas_remaining(),
addr,
value,
input_offset: buf.offset(),
input_len: buf.len(),
output_offset: buf.offset(),
output_len: buf.len()
) == 1
}
}

pub fn emit<T: Emittable>(mut self, _ val: T) {
val.emit(OutOfReachMarker())
}
}
}
16 changes: 8 additions & 8 deletions crates/library/std/src/evm.fe
Original file line number Diff line number Diff line change
Expand Up @@ -155,20 +155,20 @@ pub fn xor(_ x: u256, _ y: u256) -> u256 {
unsafe { return __xor(x, y) }
}

pub fn byte(offset: u256, _ x: u256) -> u256 {
unsafe { return __byte(offset, x) }
pub fn byte(offset: u256, value: u256) -> u256 {
unsafe { return __byte(offset, value) }
}

pub fn shl(_ x: u256, _ y: u256) -> u256 {
unsafe { return __shl(x, y) }
pub fn shl(bits: u256, value: u256) -> u256 {
unsafe { return __shl(bits, value) }
}

pub fn shr(_ x: u256, _ y: u256) -> u256 {
unsafe { return __shr(x, y) }
pub fn shr(bits: u256, value: u256) -> u256 {
unsafe { return __shr(bits, value) }
}

pub fn sar(_ x: u256, _ y: u256) -> u256 {
unsafe { return __sar(x, y) }
pub fn sar(bits: u256, value: u256) -> u256 {
unsafe { return __sar(bits, value) }
}


Expand Down
Loading

0 comments on commit b2c4370

Please sign in to comment.