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

EIP-663: Unlimited SWAP and DUP instructions #129

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
8 changes: 4 additions & 4 deletions etk-asm/src/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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};
Expand Down Expand Up @@ -185,7 +185,7 @@ impl From<Vec<u8>> 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;
Expand Down Expand Up @@ -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};

Expand Down
2 changes: 1 addition & 1 deletion etk-asm/src/ast.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down
6 changes: 3 additions & 3 deletions etk-asm/src/disasm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ mod error {
}
}

use etk_ops::cancun::Op;
use etk_ops::prague::Op;

pub use self::error::Error;

Expand Down Expand Up @@ -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;
///
Expand Down Expand Up @@ -158,7 +158,7 @@ impl Disassembler {

#[cfg(test)]
mod tests {
use etk_ops::cancun::*;
use etk_ops::prague::*;

use hex_literal::hex;

Expand Down
4 changes: 2 additions & 2 deletions etk-asm/src/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand Down Expand Up @@ -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};
Expand Down
6 changes: 4 additions & 2 deletions etk-asm/src/parse/asm.pest
Original file line number Diff line number Diff line change
Expand Up @@ -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 //
Expand All @@ -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' }
Expand Down
32 changes: 30 additions & 2 deletions etk-asm/src/parse/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use self::{
};
use crate::ast::Node;
use crate::ops::AbstractOp;
use etk_ops::cancun::Op;
use etk_ops::prague::{DupN, Op, SwapN};
use num_bigint::BigInt;
use pest::{iterators::Pair, Parser};

Expand All @@ -48,6 +48,7 @@ fn parse_abstract_op(pair: Pair<Rule>) -> Result<AbstractOp, ParseError> {
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();
Expand Down Expand Up @@ -78,6 +79,20 @@ fn parse_push(pair: Pair<Rule>) -> Result<AbstractOp, ParseError> {
Ok(AbstractOp::Op(spec.with(expr).unwrap()))
}

fn parse_swapn_dupn(pair: Pair<Rule>) -> Result<AbstractOp, ParseError> {
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::*;
Expand All @@ -86,7 +101,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;
Expand Down Expand Up @@ -596,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);
}
}
3 changes: 3 additions & 0 deletions etk-asm/tests/asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,9 @@ fn every_op() -> Result<(), Error> {
a3
a4

b5 aabbccddeeff0011
b6 aabbccddeeff0011

f0
f1
f2
Expand Down
3 changes: 3 additions & 0 deletions etk-asm/tests/asm/every-op/main.etk
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,9 @@ log2
log3
log4

dupn 0xAABBCCDDEEFF0011
swapn 0xAABBCCDDEEFF0011

create
call
callcode
Expand Down
11 changes: 9 additions & 2 deletions etk-dasm/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
[package]
name = "etk-dasm"
version = "0.4.0-dev"
authors = ["Sam Wilson <[email protected]>", "lightclient <[email protected]>"]
authors = [
"Sam Wilson <[email protected]>",
"lightclient <[email protected]>",
]
license = "MIT OR Apache-2.0"
edition = "2018"
description = "EVM Toolkit disassembler"
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"]
Expand Down
4 changes: 2 additions & 2 deletions etk-dasm/src/bin/disease/selectors.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use etk_4byte::reverse_selector;

use etk_ops::cancun::{Op, Operation};
use etk_ops::prague::{Op, Operation};

use std::fmt;

Expand Down Expand Up @@ -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;

Expand Down
10 changes: 7 additions & 3 deletions etk-dasm/src/blocks/annotated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -659,6 +659,12 @@ impl<'a> Annotator<'a> {
let _topic3 = stack.pop();
}

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),
Op::Swap3(_) => stack.swap(3),
Expand Down Expand Up @@ -837,8 +843,6 @@ impl<'a> Annotator<'a> {
| Op::InvalidB2(_)
| Op::InvalidB3(_)
| Op::InvalidB4(_)
| Op::InvalidB5(_)
| Op::InvalidB6(_)
| Op::InvalidB7(_)
| Op::InvalidB8(_)
| Op::InvalidB9(_)
Expand Down
4 changes: 2 additions & 2 deletions etk-dasm/src/blocks/basic.rs
Original file line number Diff line number Diff line change
@@ -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)]
Expand Down Expand Up @@ -107,7 +107,7 @@ impl Separator {

#[cfg(test)]
mod tests {
use etk_ops::cancun::*;
use etk_ops::prague::*;

use super::*;

Expand Down
44 changes: 10 additions & 34 deletions etk-ops/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -680,41 +685,11 @@ fn generate_fork(fork_name: &str) -> Result<(), Error> {
T: ?Sized + super::Immediates,
#(I: TryInto<T::#bounds, Error = E>,)*
{
// 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)
Expand Down Expand Up @@ -852,4 +827,5 @@ fn main() {
generate_fork("london").unwrap();
generate_fork("shanghai").unwrap();
generate_fork("cancun").unwrap();
generate_fork("prague").unwrap();
}
5 changes: 5 additions & 0 deletions etk-ops/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
Loading
Loading