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

feat(codegen): dispatching functions with function dispatcher #153

Merged
merged 10 commits into from
Oct 24, 2023
86 changes: 31 additions & 55 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ indexmap = "2.0.0"
once_cell = "1.18.0"
parking_lot = "0.12.1"
paste = "1.0.13"
postcard = { version = "1.0.8", default-features = false }
proc-macro2 = "1.0.69"
quote = "1.0.33"
revm = "3.5.0"
Expand Down
4 changes: 4 additions & 0 deletions codegen/abi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,8 @@ license.workspace = true
repository.workspace = true

[dependencies]
hex.workspace = true
postcard = { workspace = true, default-features = false, features = [ "use-std" ] }
serde = { workspace = true, features = [ "derive" ] }
sha3.workspace = true
thiserror.workspace = true
54 changes: 54 additions & 0 deletions codegen/abi/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
//! Utils for generating of zink ABI
pub use self::result::{Error, Result};
use serde::{Deserialize, Serialize};
use sha3::{Digest, Keccak256};

mod result;

/// Generate a keccak hash of the input (sha3)
pub fn keccak256(input: &[u8]) -> [u8; 32] {
let mut hasher = Keccak256::new();
Expand All @@ -15,3 +19,53 @@ pub fn selector(input: &[u8]) -> [u8; 4] {

selector
}

/// Function ABI.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Abi {
/// Function name.
pub name: String,
/// Function inputs.
pub inputs: Vec<String>,
}

impl Abi {
/// Get function signature.
pub fn signature(&self) -> String {
self.name.clone() + "(" + &self.inputs.join(",") + ")"
}

/// Get function selector.
pub fn selector(&self) -> [u8; 4] {
let sig = self.signature();
let mut selector = [0u8; 4];
selector.copy_from_slice(&keccak256(sig.as_bytes())[..4]);

selector
}

/// Parse ABI from bytes.
pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
postcard::from_bytes(bytes).map_err(Into::into)
}

/// Decode ABI form hex string.
pub fn from_hex(hex: &str) -> Result<Self> {
Self::from_bytes(&hex::decode(hex)?)
}

/// Decode ABI form hex string.
pub fn from_hex_bytes(bytes: &[u8]) -> Result<Self> {
Self::from_hex(&String::from_utf8_lossy(bytes))
}

/// Convert ABI to hex string.
pub fn to_hex(&self) -> Result<String> {
self.to_bytes().map(hex::encode)
}

/// Convert ABI to bytes.
pub fn to_bytes(&self) -> Result<Vec<u8>> {
postcard::to_stdvec(&self).map_err(Into::into)
}
}
15 changes: 15 additions & 0 deletions codegen/abi/src/result.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
//! Abi results

/// ABI error
#[derive(Debug, thiserror::Error)]
pub enum Error {
/// Failed to encode or decode with postcard.
#[error(transparent)]
Postcard(#[from] postcard::Error),
/// Failed to decode from hex.
#[error(transparent)]
Hex(#[from] hex::FromHexError),
}

/// ABI result
pub type Result<T> = std::result::Result<T, Error>;
1 change: 1 addition & 0 deletions codegen/src/abi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ macro_rules! offset {

offset! {
(usize, 8),
(u64, 8),
(i64, 8),
(i32, 4),
(u32, 4),
Expand Down
4 changes: 2 additions & 2 deletions codegen/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use crate::{Buffer, Error, Result};
use opcodes::{for_each_shanghai_operator, OpCode as _, ShangHai as OpCode};

/// Low level assembler implementation for EVM.
#[derive(Default)]
#[derive(Default, Clone)]
pub struct Assembler {
/// Buffer of the assembler.
buffer: Buffer,
Expand Down Expand Up @@ -97,7 +97,7 @@ impl Assembler {
/// Mock the stack input and output for checking
/// the stack usages.
pub fn emit_op(&mut self, opcode: OpCode) -> Result<()> {
tracing::trace!("stack length: {:?}", self.sp);
// tracing::trace!("stack length: {:?}", self.sp);
tracing::trace!("emit opcode: {:?}", opcode);
self.decrement_sp(opcode.stack_in() as u8)?;
self.emit(opcode.into());
Expand Down
30 changes: 17 additions & 13 deletions codegen/src/backtrace.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
//! Backtrace support for the code generation.
use std::collections::BTreeMap;

/// Backtrace implementation for the code generation.
///
/// TODO: full implementation #21
#[derive(Default)]
/// TODO: full implementation (#21)
#[derive(Debug, Default)]
pub struct Backtrace {
/// The length of each operand.
len: Vec<usize>,
/// Compiled instructions.
///
/// TODO: Transform this into Opcodes. (#21)
instrs: BTreeMap<usize, Vec<u8>>,
}

impl Backtrace {
/// Pushes a new operand to the backtrace.
pub fn push(&mut self, len: usize) {
self.len.push(len);
/// Pushes a new instruction set to the backtrace.
pub fn push(&mut self, bytes: impl AsRef<[u8]>) {
self.instrs.insert(self.instrs.len(), bytes.as_ref().into());
}

/// Pops the last operand from the backtrace.
pub fn pop(&mut self) -> usize {
self.len.pop().unwrap_or_default()
/// Pops the last instruction from the backtrace.
pub fn pop(&mut self) -> Vec<u8> {
self.instrs.pop_last().unwrap_or_default().1
}

pub fn popn(&mut self, n: usize) -> usize {
let mut r: Vec<usize> = Default::default();
/// Pop the last `n` operands from the backtrace.
pub fn popn(&mut self, n: usize) -> Vec<Vec<u8>> {
let mut r: Vec<Vec<u8>> = Default::default();

while r.len() < n {
r.push(self.pop())
}

r.into_iter().sum()
r
}
}
45 changes: 45 additions & 0 deletions codegen/src/code/func.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//! External Function for the code section.
use opcodes::ShangHai as OpCode;

trait OpCodesToBytes {
fn to_bytes(self) -> Vec<u8>;
}

impl OpCodesToBytes for &[OpCode] {
fn to_bytes(self) -> Vec<u8> {
[&[OpCode::JUMPDEST], self]
.concat()
.iter()
.map(|op| (*op).into())
.collect()
}
}

/// External function in code section.
#[derive(PartialEq, Eq, Debug, Clone, Hash)]
pub struct ExtFunc {
/// Stack input.
pub stack_out: u8,
/// Stack output.
pub stack_in: u8,
/// The bytecode of the external function.
pub bytecode: Vec<u8>,
}

impl ExtFunc {
/// Function select.
pub fn select() -> Self {
Self {
stack_in: 2,
stack_out: 1,
bytecode: [
OpCode::POP,
OpCode::PUSH1,
OpCode::Data(0x06),
OpCode::ADD,
OpCode::JUMP,
]
.to_bytes(),
}
}
}
Loading