From 0833b734ed040fc8664d768fa8e86ec5deabe497 Mon Sep 17 00:00:00 2001 From: Gaston Zanitti Date: Thu, 31 Aug 2023 17:25:00 -0300 Subject: [PATCH 1/3] EIP-4750: Functions. Basic skeleton --- etk-asm/src/asm.rs | 8 +- etk-asm/src/ast.rs | 2 +- etk-asm/src/disasm.rs | 6 +- etk-asm/src/ops.rs | 4 +- etk-asm/src/parse/mod.rs | 4 +- etk-dasm/src/bin/disease/selectors.rs | 4 +- etk-dasm/src/blocks/annotated.rs | 18 +- etk-dasm/src/blocks/basic.rs | 4 +- etk-ops/build.rs | 44 +- etk-ops/src/lib.rs | 5 + etk-ops/src/prague.toml | 922 ++++++++++++++++++++++++++ 11 files changed, 968 insertions(+), 53 deletions(-) create mode 100644 etk-ops/src/prague.toml diff --git a/etk-asm/src/asm.rs b/etk-asm/src/asm.rs index a0555961..6acc7351 100644 --- a/etk-asm/src/asm.rs +++ b/etk-asm/src/asm.rs @@ -6,7 +6,7 @@ mod error { use crate::ops::Expression; use crate::ParseError; - use etk_ops::cancun::Op; + use etk_ops::prague::Op; use num_bigint::BigInt; use snafu::{Backtrace, Snafu}; @@ -132,7 +132,7 @@ mod error { pub use self::error::Error; use crate::ops::expression::{self, Terminal}; use crate::ops::{self, AbstractOp, Assemble, Expression, Imm, MacroDefinition}; -use etk_ops::cancun::Op; +use etk_ops::prague::Op; use rand::Rng; use snafu::OptionExt; use std::collections::{hash_map, HashMap, HashSet, VecDeque}; @@ -185,7 +185,7 @@ impl From> for RawOp { /// ```rust /// use etk_asm::asm::Assembler; /// use etk_asm::ops::AbstractOp; -/// use etk_ops::cancun::{Op, GetPc}; +/// use etk_ops::prague::{Op, GetPc}; /// # use etk_asm::asm::Error; /// # /// # use hex_literal::hex; @@ -711,7 +711,7 @@ mod tests { InstructionMacroDefinition, InstructionMacroInvocation, Terminal, }; use assert_matches::assert_matches; - use etk_ops::cancun::*; + use etk_ops::prague::*; use hex_literal::hex; use num_bigint::{BigInt, Sign}; diff --git a/etk-asm/src/ast.rs b/etk-asm/src/ast.rs index a4d2e15d..9cd3a3a6 100644 --- a/etk-asm/src/ast.rs +++ b/etk-asm/src/ast.rs @@ -1,5 +1,5 @@ use crate::ops::{Abstract, AbstractOp, ExpressionMacroDefinition, InstructionMacroDefinition}; -use etk_ops::cancun::Op; +use etk_ops::prague::Op; use std::path::PathBuf; #[derive(Debug, Clone, PartialEq)] diff --git a/etk-asm/src/disasm.rs b/etk-asm/src/disasm.rs index bad65da2..4f6caf9b 100644 --- a/etk-asm/src/disasm.rs +++ b/etk-asm/src/disasm.rs @@ -25,7 +25,7 @@ mod error { } } -use etk_ops::cancun::Op; +use etk_ops::prague::Op; pub use self::error::Error; @@ -96,7 +96,7 @@ impl<'a> Iterator for Iter<'a> { /// /// ## Example /// ```rust -/// use etk_ops::cancun::{Op, GetPc, Stop}; +/// use etk_ops::prague::{Op, GetPc, Stop}; /// use etk_asm::disasm::Disassembler; /// # use etk_asm::disasm::Offset; /// @@ -158,7 +158,7 @@ impl Disassembler { #[cfg(test)] mod tests { - use etk_ops::cancun::*; + use etk_ops::prague::*; use hex_literal::hex; diff --git a/etk-asm/src/ops.rs b/etk-asm/src/ops.rs index 1749459a..0c202c36 100644 --- a/etk-asm/src/ops.rs +++ b/etk-asm/src/ops.rs @@ -2,7 +2,7 @@ mod error { use super::expression; - use etk_ops::cancun::Op; + use etk_ops::prague::Op; use num_bigint::BigInt; use snafu::{Backtrace, Snafu}; @@ -43,7 +43,7 @@ mod types; pub(crate) use self::error::Error; -use etk_ops::cancun::{Op, Operation, Push32}; +use etk_ops::prague::{Op, Operation, Push32}; pub use self::error::UnknownSpecifierError; pub use self::expression::{Context, Expression, Terminal}; diff --git a/etk-asm/src/parse/mod.rs b/etk-asm/src/parse/mod.rs index dba643c7..0ec5e53b 100644 --- a/etk-asm/src/parse/mod.rs +++ b/etk-asm/src/parse/mod.rs @@ -21,7 +21,7 @@ use self::{ }; use crate::ast::Node; use crate::ops::AbstractOp; -use etk_ops::cancun::Op; +use etk_ops::prague::Op; use num_bigint::BigInt; use pest::{iterators::Pair, Parser}; @@ -86,7 +86,7 @@ mod tests { InstructionMacroDefinition, InstructionMacroInvocation, Terminal, }; use assert_matches::assert_matches; - use etk_ops::cancun::*; + use etk_ops::prague::*; use hex_literal::hex; use num_bigint::Sign; use std::path::PathBuf; diff --git a/etk-dasm/src/bin/disease/selectors.rs b/etk-dasm/src/bin/disease/selectors.rs index ad21a6c9..d1caa135 100644 --- a/etk-dasm/src/bin/disease/selectors.rs +++ b/etk-dasm/src/bin/disease/selectors.rs @@ -1,6 +1,6 @@ use etk_4byte::reverse_selector; -use etk_ops::cancun::{Op, Operation}; +use etk_ops::prague::{Op, Operation}; use std::fmt; @@ -69,7 +69,7 @@ impl fmt::Display for DisplayOp { #[cfg(test)] mod tests { - use etk_ops::cancun::*; + use etk_ops::prague::*; use hex_literal::hex; diff --git a/etk-dasm/src/blocks/annotated.rs b/etk-dasm/src/blocks/annotated.rs index 382c17e3..0540938a 100644 --- a/etk-dasm/src/blocks/annotated.rs +++ b/etk-dasm/src/blocks/annotated.rs @@ -2,7 +2,7 @@ //! (ie. stack/memory/storage). use crate::sym::{Expr, Var}; -use etk_ops::cancun::*; +use etk_ops::prague::*; use std::collections::VecDeque; @@ -659,6 +659,20 @@ impl<'a> Annotator<'a> { let _topic3 = stack.pop(); } + Op::Callf(Callf(imm)) => { + // Return stack: + // ( + // code_section_index (imm) = current_section_index, + // offset = PC_post_instruction, + // stack_height = data_stack.height - types[code_section_index].inputs + // ) + // PC = 0; + } + + Op::Retf(_) => { + // Pops an item from return stack and sets `current_section_index` and `PC` to values from this item. + } + Op::Swap1(_) => stack.swap(1), Op::Swap2(_) => stack.swap(2), Op::Swap3(_) => stack.swap(3), @@ -883,8 +897,6 @@ impl<'a> Annotator<'a> { | Op::InvalidE0(_) | Op::InvalidE1(_) | Op::InvalidE2(_) - | Op::InvalidE3(_) - | Op::InvalidE4(_) | Op::InvalidE5(_) | Op::InvalidE6(_) | Op::InvalidE7(_) diff --git a/etk-dasm/src/blocks/basic.rs b/etk-dasm/src/blocks/basic.rs index ee0b2abf..d00de6c5 100644 --- a/etk-dasm/src/blocks/basic.rs +++ b/etk-dasm/src/blocks/basic.rs @@ -1,7 +1,7 @@ //! A list of EVM instructions with a single point of entry and a single exit. use etk_asm::disasm::Offset; -use etk_ops::cancun::{Op, Operation}; +use etk_ops::prague::{Op, Operation}; /// A list of EVM instructions with a single point of entry and a single exit. #[derive(Debug, Eq, PartialEq)] @@ -107,7 +107,7 @@ impl Separator { #[cfg(test)] mod tests { - use etk_ops::cancun::*; + use etk_ops::prague::*; use super::*; diff --git a/etk-ops/build.rs b/etk-ops/build.rs index 97699974..b569f4cd 100644 --- a/etk-ops/build.rs +++ b/etk-ops/build.rs @@ -167,6 +167,11 @@ fn generate_fork(fork_name: &str) -> Result<(), Error> { let mut immediate_mut_matches = quote! {}; let mut into_immediate_matches = quote! {}; let names: Vec<_> = ops.iter().map(|(n, _)| format_ident!("{}", n)).collect(); + let immediate_ops: Vec<_> = ops + .iter() + .filter(|(_, op)| op.extra_len > 0) + .map(|(n, _)| format_ident!("{}", n)) + .collect(); for (name, op) in &ops { let name = format_ident!("{}", name); @@ -680,41 +685,11 @@ fn generate_fork(fork_name: &str) -> Result<(), Error> { T: ?Sized + super::Immediates, #(I: TryInto,)* { - // TODO: Automate generating these? let result = match self { - Self::Push1(_) => Op::Push1(Push1(immediate.try_into()?)), - Self::Push2(_) => Op::Push2(Push2(immediate.try_into()?)), - Self::Push3(_) => Op::Push3(Push3(immediate.try_into()?)), - Self::Push4(_) => Op::Push4(Push4(immediate.try_into()?)), - Self::Push5(_) => Op::Push5(Push5(immediate.try_into()?)), - Self::Push6(_) => Op::Push6(Push6(immediate.try_into()?)), - Self::Push7(_) => Op::Push7(Push7(immediate.try_into()?)), - Self::Push8(_) => Op::Push8(Push8(immediate.try_into()?)), - Self::Push9(_) => Op::Push9(Push9(immediate.try_into()?)), - Self::Push10(_) => Op::Push10(Push10(immediate.try_into()?)), - Self::Push11(_) => Op::Push11(Push11(immediate.try_into()?)), - Self::Push12(_) => Op::Push12(Push12(immediate.try_into()?)), - Self::Push13(_) => Op::Push13(Push13(immediate.try_into()?)), - Self::Push14(_) => Op::Push14(Push14(immediate.try_into()?)), - Self::Push15(_) => Op::Push15(Push15(immediate.try_into()?)), - Self::Push16(_) => Op::Push16(Push16(immediate.try_into()?)), - Self::Push17(_) => Op::Push17(Push17(immediate.try_into()?)), - Self::Push18(_) => Op::Push18(Push18(immediate.try_into()?)), - Self::Push19(_) => Op::Push19(Push19(immediate.try_into()?)), - Self::Push20(_) => Op::Push20(Push20(immediate.try_into()?)), - Self::Push21(_) => Op::Push21(Push21(immediate.try_into()?)), - Self::Push22(_) => Op::Push22(Push22(immediate.try_into()?)), - Self::Push23(_) => Op::Push23(Push23(immediate.try_into()?)), - Self::Push24(_) => Op::Push24(Push24(immediate.try_into()?)), - Self::Push25(_) => Op::Push25(Push25(immediate.try_into()?)), - Self::Push26(_) => Op::Push26(Push26(immediate.try_into()?)), - Self::Push27(_) => Op::Push27(Push27(immediate.try_into()?)), - Self::Push28(_) => Op::Push28(Push28(immediate.try_into()?)), - Self::Push29(_) => Op::Push29(Push29(immediate.try_into()?)), - Self::Push30(_) => Op::Push30(Push30(immediate.try_into()?)), - Self::Push31(_) => Op::Push31(Push31(immediate.try_into()?)), - Self::Push32(_) => Op::Push32(Push32(immediate.try_into()?)), - _ => panic!("only push operations can be combined"), + #( + Self::#immediate_ops(_) => Op::#immediate_ops(#immediate_ops(immediate.try_into()?)), + )* + _ => panic!("only relative jumps/push operations can be combined"), }; Ok(result) @@ -852,4 +827,5 @@ fn main() { generate_fork("london").unwrap(); generate_fork("shanghai").unwrap(); generate_fork("cancun").unwrap(); + generate_fork("prague").unwrap(); } diff --git a/etk-ops/src/lib.rs b/etk-ops/src/lib.rs index 52520016..fda655b1 100644 --- a/etk-ops/src/lib.rs +++ b/etk-ops/src/lib.rs @@ -29,6 +29,11 @@ pub mod cancun { include!(concat!(env!("OUT_DIR"), "/cancun.rs")); } +pub mod prague { + //! Instructions available in the London hard fork. + include!(concat!(env!("OUT_DIR"), "/prague.rs")); +} + /// Error that can occur when parsing an operation from a string. #[derive(Debug, Snafu)] pub struct FromStrError { diff --git a/etk-ops/src/prague.toml b/etk-ops/src/prague.toml new file mode 100644 index 00000000..4673cfa4 --- /dev/null +++ b/etk-ops/src/prague.toml @@ -0,0 +1,922 @@ +[Stop] +code = 0x00 +mnemonic = "stop" +pushes = 0 +pops = 0 +exits = true + +[Add] +code = 0x01 +mnemonic = "add" +pushes = 1 +pops = 2 + +[Mul] +code = 0x02 +mnemonic = "mul" +pushes = 1 +pops = 2 + +[Sub] +code = 0x03 +mnemonic = "sub" +pushes = 1 +pops = 2 + +[Div] +code = 0x04 +mnemonic = "div" +pushes = 1 +pops = 2 + +[SDiv] +code = 0x05 +mnemonic = "sdiv" +pushes = 1 +pops = 2 + +[Mod] +code = 0x06 +mnemonic = "mod" +pushes = 1 +pops = 2 + +[SMod] +code = 0x07 +mnemonic = "smod" +pushes = 1 +pops = 2 + +[AddMod] +code = 0x08 +mnemonic = "addmod" +pushes = 1 +pops = 3 + +[MulMod] +code = 0x09 +mnemonic = "mulmod" +pushes = 1 +pops = 3 + +[Exp] +code = 0x0a +mnemonic = "exp" +pushes = 1 +pops = 2 + +[SignExtend] +code = 0x0b +mnemonic = "signextend" +pushes = 1 +pops = 2 + +[Lt] +code = 0x10 +mnemonic = "lt" +pushes = 1 +pops = 2 + +[Gt] +code = 0x11 +mnemonic = "gt" +pushes = 1 +pops = 2 + +[SLt] +code = 0x12 +mnemonic = "slt" +pushes = 1 +pops = 2 + +[SGt] +code = 0x13 +mnemonic = "sgt" +pushes = 1 +pops = 2 + +[Eq] +code = 0x14 +mnemonic = "eq" +pushes = 1 +pops = 2 + +[IsZero] +code = 0x15 +mnemonic = "iszero" +pushes = 1 +pops = 1 + +[And] +code = 0x16 +mnemonic = "and" +pushes = 1 +pops = 2 + +[Or] +code = 0x17 +mnemonic = "or" +pushes = 1 +pops = 2 + +[Xor] +code = 0x18 +mnemonic = "xor" +pushes = 1 +pops = 2 + +[Not] +code = 0x19 +mnemonic = "not" +pushes = 1 +pops = 1 + +[Byte] +code = 0x1a +mnemonic = "byte" +pushes = 1 +pops = 2 + +[Shl] +code = 0x1b +mnemonic = "shl" +pushes = 1 +pops = 2 + +[Shr] +code = 0x1c +mnemonic = "shr" +pushes = 1 +pops = 2 + +[Sar] +code = 0x1d +mnemonic = "sar" +pushes = 1 +pops = 2 + +[Keccak256] +code = 0x20 +mnemonic = "keccak256" +pushes = 1 +pops = 2 + +[Address] +code = 0x30 +mnemonic = "address" +pushes = 1 +pops = 0 + +[Balance] +code = 0x31 +mnemonic = "balance" +pushes = 1 +pops = 1 + +[Origin] +code = 0x32 +mnemonic = "origin" +pushes = 1 +pops = 0 + +[Caller] +code = 0x33 +mnemonic = "caller" +pushes = 1 +pops = 0 + +[CallValue] +code = 0x34 +mnemonic = "callvalue" +pushes = 1 +pops = 0 + +[CallDataLoad] +code = 0x35 +mnemonic = "calldataload" +pushes = 1 +pops = 1 + +[CallDataSize] +code = 0x36 +mnemonic = "calldatasize" +pushes = 1 +pops = 0 + +[CallDataCopy] +code = 0x37 +mnemonic = "calldatacopy" +pushes = 0 +pops = 3 + +[CodeSize] +code = 0x38 +mnemonic = "codesize" +pushes = 1 +pops = 0 + +[CodeCopy] +code = 0x39 +mnemonic = "codecopy" +pushes = 0 +pops = 3 + +[GasPrice] +code = 0x3a +mnemonic = "gasprice" +pushes = 1 +pops = 0 + +[ExtCodeSize] +code = 0x3b +mnemonic = "extcodesize" +pushes = 1 +pops = 1 + +[ExtCodeCopy] +code = 0x3c +mnemonic = "extcodecopy" +pushes = 0 +pops = 4 + +[ReturnDataSize] +code = 0x3d +mnemonic = "returndatasize" +pushes = 1 +pops = 0 + +[ReturnDataCopy] +code = 0x3e +mnemonic = "returndatacopy" +pushes = 0 +pops = 3 + +[ExtCodeHash] +code = 0x3f +mnemonic = "extcodehash" +pushes = 1 +pops = 1 + +[BlockHash] +code = 0x40 +mnemonic = "blockhash" +pushes = 1 +pops = 1 + +[Coinbase] +code = 0x41 +mnemonic = "coinbase" +pushes = 1 +pops = 0 + +[Timestamp] +code = 0x42 +mnemonic = "timestamp" +pushes = 1 +pops = 0 + +[Number] +code = 0x43 +mnemonic = "number" +pushes = 1 +pops = 0 + +[Difficulty] +code = 0x44 +mnemonic = "difficulty" +pushes = 1 +pops = 0 + +[GasLimit] +code = 0x45 +mnemonic = "gaslimit" +pushes = 1 +pops = 0 + +[ChainId] +code = 0x46 +mnemonic = "chainid" +pushes = 1 +pops = 0 + +[SelfBalance] +code = 0x47 +mnemonic = "selfbalance" +pushes = 1 +pops = 0 + +[BaseFee] +code = 0x48 +mnemonic = "basefee" +pushes = 1 +pops = 0 + +[Pop] +code = 0x50 +mnemonic = "pop" +pushes = 0 +pops = 1 + +[MLoad] +code = 0x51 +mnemonic = "mload" +pushes = 1 +pops = 1 + +[MStore] +code = 0x52 +mnemonic = "mstore" +pushes = 0 +pops = 2 + +[MStore8] +code = 0x53 +mnemonic = "mstore8" +pushes = 1 +pops = 2 + +[SLoad] +code = 0x54 +mnemonic = "sload" +pushes = 1 +pops = 1 + +[SStore] +code = 0x55 +mnemonic = "sstore" +pushes = 0 +pops = 2 + +[Jump] +code = 0x56 +mnemonic = "jump" +pushes = 0 +pops = 1 +jump = true + +[JumpI] +code = 0x57 +mnemonic = "jumpi" +pushes = 0 +pops = 2 +jump = true + +[GetPc] +code = 0x58 +mnemonic = "pc" +pushes = 1 +pops = 0 + +[MSize] +code = 0x59 +mnemonic = "msize" +pushes = 1 +pops = 0 + +[Gas] +code = 0x5a +mnemonic = "gas" +pushes = 1 +pops = 0 + +[JumpDest] +code = 0x5b +mnemonic = "jumpdest" +pushes = 0 +pops = 0 +jump_target = true + +[MCopy] +code = 0x5e +mnemonic = "mcopy" +pushes = 0 +pops = 3 + +[Push0] +code = 0x5f +mnemonic = "push0" +extra_len = 0 +pushes = 1 +pops = 0 + +[Push1] +code = 0x60 +mnemonic = "push1" +extra_len = 1 +pushes = 1 +pops = 0 + +[Push2] +code = 0x61 +mnemonic = "push2" +extra_len = 2 +pushes = 1 +pops = 0 + +[Push3] +code = 0x62 +mnemonic = "push3" +extra_len = 3 +pushes = 1 +pops = 0 + +[Push4] +code = 0x63 +mnemonic = "push4" +extra_len = 4 +pushes = 1 +pops = 0 + +[Push5] +code = 0x64 +mnemonic = "push5" +extra_len = 5 +pushes = 1 +pops = 0 + +[Push6] +code = 0x65 +mnemonic = "push6" +extra_len = 6 +pushes = 1 +pops = 0 + +[Push7] +code = 0x66 +mnemonic = "push7" +extra_len = 7 +pushes = 1 +pops = 0 + +[Push8] +code = 0x67 +mnemonic = "push8" +extra_len = 8 +pushes = 1 +pops = 0 + +[Push9] +code = 0x68 +mnemonic = "push9" +extra_len = 9 +pushes = 1 +pops = 0 + +[Push10] +code = 0x69 +mnemonic = "push10" +extra_len = 10 +pushes = 1 +pops = 0 + +[Push11] +code = 0x6a +mnemonic = "push11" +extra_len = 11 +pushes = 1 +pops = 0 + +[Push12] +code = 0x6b +mnemonic = "push12" +extra_len = 12 +pushes = 1 +pops = 0 + +[Push13] +code = 0x6c +mnemonic = "push13" +extra_len = 13 +pushes = 1 +pops = 0 + +[Push14] +code = 0x6d +mnemonic = "push14" +extra_len = 14 +pushes = 1 +pops = 0 + +[Push15] +code = 0x6e +mnemonic = "push15" +extra_len = 15 +pushes = 1 +pops = 0 + +[Push16] +code = 0x6f +mnemonic = "push16" +extra_len = 16 +pushes = 1 +pops = 0 + +[Push17] +code = 0x70 +mnemonic = "push17" +extra_len = 17 +pushes = 1 +pops = 0 + +[Push18] +code = 0x71 +mnemonic = "push18" +extra_len = 18 +pushes = 1 +pops = 0 + +[Push19] +code = 0x72 +mnemonic = "push19" +extra_len = 19 +pushes = 1 +pops = 0 + +[Push20] +code = 0x73 +mnemonic = "push20" +extra_len = 20 +pushes = 1 +pops = 0 + +[Push21] +code = 0x74 +mnemonic = "push21" +extra_len = 21 +pushes = 1 +pops = 0 + +[Push22] +code = 0x75 +mnemonic = "push22" +extra_len = 22 +pushes = 1 +pops = 0 + +[Push23] +code = 0x76 +mnemonic = "push23" +extra_len = 23 +pushes = 1 +pops = 0 + +[Push24] +code = 0x77 +mnemonic = "push24" +extra_len = 24 +pushes = 1 +pops = 0 + +[Push25] +code = 0x78 +mnemonic = "push25" +extra_len = 25 +pushes = 1 +pops = 0 + +[Push26] +code = 0x79 +mnemonic = "push26" +extra_len = 26 +pushes = 1 +pops = 0 + +[Push27] +code = 0x7a +mnemonic = "push27" +extra_len = 27 +pushes = 1 +pops = 0 + +[Push28] +code = 0x7b +mnemonic = "push28" +extra_len = 28 +pushes = 1 +pops = 0 + +[Push29] +code = 0x7c +mnemonic = "push29" +extra_len = 29 +pushes = 1 +pops = 0 + +[Push30] +code = 0x7d +mnemonic = "push30" +extra_len = 30 +pushes = 1 +pops = 0 + +[Push31] +code = 0x7e +mnemonic = "push31" +extra_len = 31 +pushes = 1 +pops = 0 + +[Push32] +code = 0x7f +mnemonic = "push32" +extra_len = 32 +pushes = 1 +pops = 0 + +[Dup1] +code = 0x80 +mnemonic = "dup1" +pushes = 2 +pops = 1 + +[Dup2] +code = 0x81 +mnemonic = "dup2" +pushes = 3 +pops = 2 + +[Dup3] +code = 0x82 +mnemonic = "dup3" +pushes = 4 +pops = 3 + +[Dup4] +code = 0x83 +mnemonic = "dup4" +pushes = 5 +pops = 4 + +[Dup5] +code = 0x84 +mnemonic = "dup5" +pushes = 6 +pops = 5 + +[Dup6] +code = 0x85 +mnemonic = "dup6" +pushes = 7 +pops = 6 + +[Dup7] +code = 0x86 +mnemonic = "dup7" +pushes = 8 +pops = 7 + +[Dup8] +code = 0x87 +mnemonic = "dup8" +pushes = 9 +pops = 8 + +[Dup9] +code = 0x88 +mnemonic = "dup9" +pushes = 10 +pops = 9 + +[Dup10] +code = 0x89 +mnemonic = "dup10" +pushes = 11 +pops = 10 + +[Dup11] +code = 0x8a +mnemonic = "dup11" +pushes = 12 +pops = 11 + +[Dup12] +code = 0x8b +mnemonic = "dup12" +pushes = 13 +pops = 12 + +[Dup13] +code = 0x8c +mnemonic = "dup13" +pushes = 14 +pops = 13 + +[Dup14] +code = 0x8d +mnemonic = "dup14" +pushes = 15 +pops = 14 + +[Dup15] +code = 0x8e +mnemonic = "dup15" +pushes = 16 +pops = 15 + +[Dup16] +code = 0x8f +mnemonic = "dup16" +pushes = 17 +pops = 16 + +[Swap1] +code = 0x90 +mnemonic = "swap1" +pushes = 2 +pops = 2 + +[Swap2] +code = 0x91 +mnemonic = "swap2" +pushes = 3 +pops = 3 + +[Swap3] +code = 0x92 +mnemonic = "swap3" +pushes = 4 +pops = 4 + +[Swap4] +code = 0x93 +mnemonic = "swap4" +pushes = 5 +pops = 5 + +[Swap5] +code = 0x94 +mnemonic = "swap5" +pushes = 6 +pops = 6 + +[Swap6] +code = 0x95 +mnemonic = "swap6" +pushes = 7 +pops = 7 + +[Swap7] +code = 0x96 +mnemonic = "swap7" +pushes = 8 +pops = 8 + +[Swap8] +code = 0x97 +mnemonic = "swap8" +pushes = 9 +pops = 9 + +[Swap9] +code = 0x98 +mnemonic = "swap9" +pushes = 10 +pops = 10 + +[Swap10] +code = 0x99 +mnemonic = "swap10" +pushes = 11 +pops = 11 + +[Swap11] +code = 0x9a +mnemonic = "swap11" +pushes = 12 +pops = 12 + +[Swap12] +code = 0x9b +mnemonic = "swap12" +pushes = 13 +pops = 13 + +[Swap13] +code = 0x9c +mnemonic = "swap13" +pushes = 14 +pops = 14 + +[Swap14] +code = 0x9d +mnemonic = "swap14" +pushes = 15 +pops = 15 + +[Swap15] +code = 0x9e +mnemonic = "swap15" +pushes = 16 +pops = 16 + +[Swap16] +code = 0x9f +mnemonic = "swap16" +pushes = 17 +pops = 17 + +[Log0] +code = 0xa0 +mnemonic = "log0" +pushes = 2 +pops = 2 + +[Log1] +code = 0xa1 +mnemonic = "log1" +pushes = 3 +pops = 3 + +[Log2] +code = 0xa2 +mnemonic = "log2" +pushes = 4 +pops = 4 + +[Log3] +code = 0xa3 +mnemonic = "log3" +pushes = 5 +pops = 5 + +[Log4] +code = 0xa4 +mnemonic = "log4" +pushes = 6 +pops = 6 + +[Callf] +code = 0xe3 +mnemonic = "callf" +extra_len = 16 +pushes = 0 +pops = 0 + +[Retf] +code = 0xe4 +mnemonic = "retf" +pushes = 0 +pops = 0 + +[Create] +code = 0xf0 +mnemonic = "create" +pushes = 1 +pops = 3 + +[Call] +code = 0xf1 +mnemonic = "call" +pushes = 1 +pops = 7 + +[CallCode] +code = 0xf2 +mnemonic = "callcode" +pushes = 1 +pops = 7 + +[Return] +code = 0xf3 +mnemonic = "return" +pushes = 0 +pops = 2 +exits = true + +[DelegateCall] +code = 0xf4 +mnemonic = "delegatecall" +pushes = 1 +pops = 6 + +[Create2] +code = 0xf5 +mnemonic = "create2" +pushes = 1 +pops = 4 + +[StaticCall] +code = 0xfa +mnemonic = "staticcall" +pushes = 1 +pops = 6 + +[Revert] +code = 0xfd +mnemonic = "revert" +pushes = 0 +pops = 2 +exits = true + +[Invalid] +code = 0xfe +mnemonic = "invalid" +pushes = 0 +pops = 0 +exits = true + +[SelfDestruct] +code = 0xff +mnemonic = "selfdestruct" +pushes = 0 +pops = 2 From 9cf2e151641ceb2fc7829fe7c035a84c9a8d6745 Mon Sep 17 00:00:00 2001 From: Gaston Zanitti Date: Thu, 31 Aug 2023 21:59:46 -0300 Subject: [PATCH 2/3] EIP-663: Unlimited SWAP and DUP instructions --- etk-asm/src/parse/asm.pest | 6 ++++-- etk-asm/src/parse/mod.rs | 17 ++++++++++++++++- etk-asm/tests/asm.rs | 3 +++ etk-asm/tests/asm/every-op/main.etk | 3 +++ etk-dasm/Cargo.toml | 11 +++++++++-- etk-dasm/src/blocks/annotated.rs | 20 ++++++-------------- etk-ops/src/prague.toml | 17 +++++++++-------- 7 files changed, 50 insertions(+), 27 deletions(-) diff --git a/etk-asm/src/parse/asm.pest b/etk-asm/src/parse/asm.pest index 19c9f1bd..39055f24 100644 --- a/etk-asm/src/parse/asm.pest +++ b/etk-asm/src/parse/asm.pest @@ -3,7 +3,7 @@ /////////////////////// program = _{ SOI ~ inner ~ EOI } inner = _{ NEWLINE* ~ (stmt ~ (NEWLINE+|";"))* ~ stmt? } -stmt = _{ label_definition | builtin | local_macro | push | op } +stmt = _{ label_definition | builtin | local_macro | push | swapn | dupn | op} ////////////////////// // opcode mnemonics // @@ -21,11 +21,13 @@ op = @{ "jumpi" | "jump" | "pc" | "msize" | "gas" | swap | dup | log | "create2" | "callcode" | "call" | "return" | "delegatecall" | "create" | "staticcall" | "revert" | "selfdestruct" | "byte" | "chainid" | "selfbalance" | - "basefee" | "invalid" | "push0" | "mcopy" + "basefee" | "invalid" | "push0" | "mcopy" } push = ${ "push" ~ word_size ~ WHITESPACE ~ expression } swap = @{ "swap" ~ half_word_size } dup = @{ "dup" ~ half_word_size } +swapn = ${ "swapn" ~ WHITESPACE ~ expression } +dupn = ${ "dupn" ~ WHITESPACE ~ expression } log = @{ "log" ~ '0'..'4' } word_size = @{ ('1'..'2' ~ '0'..'9') | ("3" ~ '0'..'2') | '1'..'9' } diff --git a/etk-asm/src/parse/mod.rs b/etk-asm/src/parse/mod.rs index 0ec5e53b..149dbe15 100644 --- a/etk-asm/src/parse/mod.rs +++ b/etk-asm/src/parse/mod.rs @@ -21,7 +21,7 @@ use self::{ }; use crate::ast::Node; use crate::ops::AbstractOp; -use etk_ops::prague::Op; +use etk_ops::prague::{DupN, Op, SwapN}; use num_bigint::BigInt; use pest::{iterators::Pair, Parser}; @@ -48,6 +48,7 @@ fn parse_abstract_op(pair: Pair) -> Result { AbstractOp::Label(pair.into_inner().next().unwrap().as_str().to_string()) } Rule::push => parse_push(pair)?, + Rule::swapn | Rule::dupn => parse_swapn_dupn(pair)?, Rule::op => { let spec: Op<()> = pair.as_str().parse().unwrap(); let op = Op::new(spec).unwrap(); @@ -78,6 +79,20 @@ fn parse_push(pair: Pair) -> Result { Ok(AbstractOp::Op(spec.with(expr).unwrap())) } +fn parse_swapn_dupn(pair: Pair) -> Result { + let rule = pair.as_rule(); + let mut pair = pair.into_inner(); + let n = expression::parse(pair.next().unwrap())?; + + let spec = match rule { + Rule::swapn => Op::SwapN(SwapN(n.try_into().unwrap())), + Rule::dupn => Op::DupN(DupN(n.try_into().unwrap())), + _ => unreachable!(), + }; + + Ok(AbstractOp::Op(spec)) +} + #[cfg(test)] mod tests { use super::*; diff --git a/etk-asm/tests/asm.rs b/etk-asm/tests/asm.rs index 36fc72cf..a7b39177 100644 --- a/etk-asm/tests/asm.rs +++ b/etk-asm/tests/asm.rs @@ -258,6 +258,9 @@ fn every_op() -> Result<(), Error> { a3 a4 + b5 aabbccddeeff0011 + b6 aabbccddeeff0011 + f0 f1 f2 diff --git a/etk-asm/tests/asm/every-op/main.etk b/etk-asm/tests/asm/every-op/main.etk index 5516a8cd..4a6e261d 100644 --- a/etk-asm/tests/asm/every-op/main.etk +++ b/etk-asm/tests/asm/every-op/main.etk @@ -138,6 +138,9 @@ log2 log3 log4 +dupn 0xAABBCCDDEEFF0011 +swapn 0xAABBCCDDEEFF0011 + create call callcode diff --git a/etk-dasm/Cargo.toml b/etk-dasm/Cargo.toml index 7089201a..c3ee7b64 100644 --- a/etk-dasm/Cargo.toml +++ b/etk-dasm/Cargo.toml @@ -1,7 +1,10 @@ [package] name = "etk-dasm" version = "0.4.0-dev" -authors = ["Sam Wilson ", "lightclient "] +authors = [ + "Sam Wilson ", + "lightclient ", +] license = "MIT OR Apache-2.0" edition = "2018" description = "EVM Toolkit disassembler" @@ -9,7 +12,11 @@ homepage = "https://quilt.github.io/etk" repository = "https://github.com/quilt/etk" readme = "README.md" keywords = ["etk", "ethereum", "disassembler"] -categories = ["cryptography::cryptocurrencies", "command-line-utilities", "development-tools"] +categories = [ + "cryptography::cryptocurrencies", + "command-line-utilities", + "development-tools", +] [features] cli = ["clap", "etk-cli", "snafu", "etk-4byte"] diff --git a/etk-dasm/src/blocks/annotated.rs b/etk-dasm/src/blocks/annotated.rs index 0540938a..b1de125f 100644 --- a/etk-dasm/src/blocks/annotated.rs +++ b/etk-dasm/src/blocks/annotated.rs @@ -659,19 +659,11 @@ impl<'a> Annotator<'a> { let _topic3 = stack.pop(); } - Op::Callf(Callf(imm)) => { - // Return stack: - // ( - // code_section_index (imm) = current_section_index, - // offset = PC_post_instruction, - // stack_height = data_stack.height - types[code_section_index].inputs - // ) - // PC = 0; - } - - Op::Retf(_) => { - // Pops an item from return stack and sets `current_section_index` and `PC` to values from this item. + Op::DupN(DupN(imm)) => { + let arg = stack.peek(usize::from_be_bytes(*imm)).clone(); + stack.push(arg) } + Op::SwapN(SwapN(imm)) => stack.swap(usize::from_be_bytes(*imm)), Op::Swap1(_) => stack.swap(1), Op::Swap2(_) => stack.swap(2), @@ -851,8 +843,6 @@ impl<'a> Annotator<'a> { | Op::InvalidB2(_) | Op::InvalidB3(_) | Op::InvalidB4(_) - | Op::InvalidB5(_) - | Op::InvalidB6(_) | Op::InvalidB7(_) | Op::InvalidB8(_) | Op::InvalidB9(_) @@ -897,6 +887,8 @@ impl<'a> Annotator<'a> { | Op::InvalidE0(_) | Op::InvalidE1(_) | Op::InvalidE2(_) + | Op::InvalidE3(_) + | Op::InvalidE4(_) | Op::InvalidE5(_) | Op::InvalidE6(_) | Op::InvalidE7(_) diff --git a/etk-ops/src/prague.toml b/etk-ops/src/prague.toml index 4673cfa4..d598c9f4 100644 --- a/etk-ops/src/prague.toml +++ b/etk-ops/src/prague.toml @@ -845,16 +845,17 @@ mnemonic = "log4" pushes = 6 pops = 6 -[Callf] -code = 0xe3 -mnemonic = "callf" -extra_len = 16 -pushes = 0 +[DupN] +code = 0xb5 +mnemonic = "dupn" +extra_len = 8 +pushes = 1 pops = 0 -[Retf] -code = 0xe4 -mnemonic = "retf" +[SwapN] +code = 0xb6 +mnemonic = "swapn" +extra_len = 8 pushes = 0 pops = 0 From f0c2863f4034b92f3225d3b6b39f8530eb34be52 Mon Sep 17 00:00:00 2001 From: Gaston Zanitti Date: Fri, 1 Sep 2023 10:55:31 -0300 Subject: [PATCH 3/3] SWAPN/DUPN: Parsing tests --- etk-asm/src/parse/mod.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/etk-asm/src/parse/mod.rs b/etk-asm/src/parse/mod.rs index 149dbe15..b12d6253 100644 --- a/etk-asm/src/parse/mod.rs +++ b/etk-asm/src/parse/mod.rs @@ -611,4 +611,17 @@ mod tests { ]; assert_eq!(parse_asm(&asm).unwrap(), expected); } + + #[test] + fn parse_dupn_swapn_ops() { + let asm = r#" + swapn 1 + dupn 2 + "#; + let expected = nodes![ + Op::from(SwapN(Imm::from(1u8))), + Op::from(DupN(Imm::from(2u8))) + ]; + assert_matches!(parse_asm(asm), Ok(e) if e == expected); + } }