Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
Implement some opcodes in bus-mapping (#167)
Browse files Browse the repository at this point in the history
- Implement all the opcodes already implemented in the circuit, and some
  more.
- Add convencience `map` methods to StackAddress and MemoryAddress.
- New implemented opcodes in bus-mapping:
    - All unary opcodes: ISZERO, NOT.
    - All binary opcodes: ADD, SUB, MUL, DIV, SDIV, MOD, SMOD,
      SIGNEXTEND, LT, GT, SLT, SGT, EQ, AND, OR, XOR, BYTE, SHL, SHR,
      SAR.
    - All ternary opcodes: ADDMOD, MULMOD.
    - MSTORE
    - PC
    - JUMPDEST
    - PUSH2..32
    - DUP1..16
    - SWAP1..16
  • Loading branch information
ed255 authored and CPerezz committed Nov 15, 2021
1 parent 7c6704a commit 83a6f39
Show file tree
Hide file tree
Showing 14 changed files with 910 additions and 108 deletions.
1 change: 1 addition & 0 deletions bus-mapping/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,4 @@ ethers-providers = "0.5.5"
[dev-dependencies]
url = "2.2.2"
tokio = { version = "1.13", features = ["macros"] }
pretty_assertions = "1.0.0"
5 changes: 5 additions & 0 deletions bus-mapping/src/evm/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ impl MemoryAddress {
.copy_from_slice(&bytes.as_ref()[..core::mem::size_of::<usize>()]);
Ok(MemoryAddress::from(usize::from_be_bytes(array)))
}

/// Apply a function to the contained value.
pub fn map<F: FnOnce(usize) -> usize>(&self, f: F) -> Self {
Self(f(self.0))
}
}

impl TryFrom<Word> for MemoryAddress {
Expand Down
159 changes: 153 additions & 6 deletions bus-mapping/src/evm/opcodes.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,31 @@
//! Definition of each opcode of the EVM.
mod add;
mod dup;
pub mod ids;
mod jumpdest;
mod mload;
mod mstore;
mod pc;
mod push;
mod sload;
mod stackonlyop;
mod stop;
mod swap;
use crate::circuit_input_builder::CircuitInputStateRef;
use crate::eth_types::GethExecStep;
use crate::Error;
use core::fmt::Debug;
use ids::OpcodeId;

use self::push::Push1;
use add::Add;
use self::push::Push;
use dup::Dup;
use jumpdest::Jumpdest;
use mload::Mload;
use mstore::Mstore;
use pc::Pc;
use sload::Sload;
use stackonlyop::StackOnlyOpcode;
use stop::Stop;
use swap::Swap;

/// Generic opcode trait which defines the logic of the
/// [`Operation`](crate::operation::Operation) that should be generated for an
Expand All @@ -40,11 +50,148 @@ type FnGenAssociatedOps = fn(
impl OpcodeId {
fn fn_gen_associated_ops(&self) -> FnGenAssociatedOps {
match *self {
OpcodeId::STOP => Stop::gen_associated_ops,
OpcodeId::ADD => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::MUL => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::SUB => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::DIV => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::SDIV => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::MOD => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::SMOD => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::ADDMOD => StackOnlyOpcode::<3>::gen_associated_ops,
OpcodeId::MULMOD => StackOnlyOpcode::<3>::gen_associated_ops,
OpcodeId::EXP => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::SIGNEXTEND => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::LT => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::GT => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::SLT => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::SGT => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::EQ => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::ISZERO => StackOnlyOpcode::<1>::gen_associated_ops,
OpcodeId::AND => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::OR => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::XOR => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::NOT => StackOnlyOpcode::<1>::gen_associated_ops,
OpcodeId::BYTE => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::SHL => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::SHR => StackOnlyOpcode::<2>::gen_associated_ops,
OpcodeId::SAR => StackOnlyOpcode::<2>::gen_associated_ops,
// OpcodeId::SHA3 => {},
// OpcodeId::ADDRESS => {},
// OpcodeId::BALANCE => {},
// OpcodeId::ORIGIN => {},
// OpcodeId::CALLER => {},
// OpcodeId::CALLVALUE => {},
// OpcodeId::CALLDATALOAD => {},
// OpcodeId::CALLDATASIZE => {},
// OpcodeId::CALLDATACOPY => {},
// OpcodeId::CODESIZE => {},
// OpcodeId::CODECOPY => {},
// OpcodeId::GASPRICE => {},
// OpcodeId::EXTCODESIZE => {},
// OpcodeId::EXTCODECOPY => {},
// OpcodeId::RETURNDATASIZE => {},
// OpcodeId::RETURNDATACOPY => {},
// OpcodeId::EXTCODEHASH => {},
// OpcodeId::BLOCKHASH => {},
// OpcodeId::COINBASE => {},
// OpcodeId::TIMESTAMP => {},
// OpcodeId::NUMBER => {},
// OpcodeId::DIFFICULTY => {},
// OpcodeId::GASLIMIT => {},
// OpcodeId::CHAINID => {},
// OpcodeId::SELFBALANCE => {},
// OpcodeId::BASEFEE => {},
// OpcodeId::POP => {},
OpcodeId::MLOAD => Mload::gen_associated_ops,
OpcodeId::PUSH1 => Push1::gen_associated_ops,
OpcodeId::MSTORE => Mstore::gen_associated_ops,
// OpcodeId::MSTORE8 => {}
OpcodeId::SLOAD => Sload::gen_associated_ops,
OpcodeId::STOP => Stop::gen_associated_ops,
OpcodeId::ADD => Add::gen_associated_ops,
// OpcodeId::SSTORE => {},
// OpcodeId::JUMP => {},
// OpcodeId::JUMPI => {},
OpcodeId::PC => Pc::gen_associated_ops,
// OpcodeId::MSIZE => {},
// OpcodeId::GAS => {},
OpcodeId::JUMPDEST => Jumpdest::gen_associated_ops,
OpcodeId::PUSH1 => Push::<1>::gen_associated_ops,
OpcodeId::PUSH2 => Push::<2>::gen_associated_ops,
OpcodeId::PUSH3 => Push::<3>::gen_associated_ops,
OpcodeId::PUSH4 => Push::<4>::gen_associated_ops,
OpcodeId::PUSH5 => Push::<5>::gen_associated_ops,
OpcodeId::PUSH6 => Push::<6>::gen_associated_ops,
OpcodeId::PUSH7 => Push::<7>::gen_associated_ops,
OpcodeId::PUSH8 => Push::<8>::gen_associated_ops,
OpcodeId::PUSH9 => Push::<9>::gen_associated_ops,
OpcodeId::PUSH10 => Push::<10>::gen_associated_ops,
OpcodeId::PUSH11 => Push::<11>::gen_associated_ops,
OpcodeId::PUSH12 => Push::<12>::gen_associated_ops,
OpcodeId::PUSH13 => Push::<13>::gen_associated_ops,
OpcodeId::PUSH14 => Push::<14>::gen_associated_ops,
OpcodeId::PUSH15 => Push::<15>::gen_associated_ops,
OpcodeId::PUSH16 => Push::<16>::gen_associated_ops,
OpcodeId::PUSH17 => Push::<17>::gen_associated_ops,
OpcodeId::PUSH18 => Push::<18>::gen_associated_ops,
OpcodeId::PUSH19 => Push::<19>::gen_associated_ops,
OpcodeId::PUSH20 => Push::<20>::gen_associated_ops,
OpcodeId::PUSH21 => Push::<21>::gen_associated_ops,
OpcodeId::PUSH22 => Push::<22>::gen_associated_ops,
OpcodeId::PUSH23 => Push::<23>::gen_associated_ops,
OpcodeId::PUSH24 => Push::<24>::gen_associated_ops,
OpcodeId::PUSH25 => Push::<25>::gen_associated_ops,
OpcodeId::PUSH26 => Push::<26>::gen_associated_ops,
OpcodeId::PUSH27 => Push::<27>::gen_associated_ops,
OpcodeId::PUSH28 => Push::<28>::gen_associated_ops,
OpcodeId::PUSH29 => Push::<29>::gen_associated_ops,
OpcodeId::PUSH30 => Push::<30>::gen_associated_ops,
OpcodeId::PUSH31 => Push::<31>::gen_associated_ops,
OpcodeId::PUSH32 => Push::<32>::gen_associated_ops,
OpcodeId::DUP1 => Dup::<1>::gen_associated_ops,
OpcodeId::DUP2 => Dup::<2>::gen_associated_ops,
OpcodeId::DUP3 => Dup::<3>::gen_associated_ops,
OpcodeId::DUP4 => Dup::<4>::gen_associated_ops,
OpcodeId::DUP5 => Dup::<5>::gen_associated_ops,
OpcodeId::DUP6 => Dup::<6>::gen_associated_ops,
OpcodeId::DUP7 => Dup::<7>::gen_associated_ops,
OpcodeId::DUP8 => Dup::<8>::gen_associated_ops,
OpcodeId::DUP9 => Dup::<9>::gen_associated_ops,
OpcodeId::DUP10 => Dup::<10>::gen_associated_ops,
OpcodeId::DUP11 => Dup::<11>::gen_associated_ops,
OpcodeId::DUP12 => Dup::<12>::gen_associated_ops,
OpcodeId::DUP13 => Dup::<13>::gen_associated_ops,
OpcodeId::DUP14 => Dup::<14>::gen_associated_ops,
OpcodeId::DUP15 => Dup::<15>::gen_associated_ops,
OpcodeId::DUP16 => Dup::<16>::gen_associated_ops,
OpcodeId::SWAP1 => Swap::<1>::gen_associated_ops,
OpcodeId::SWAP2 => Swap::<2>::gen_associated_ops,
OpcodeId::SWAP3 => Swap::<3>::gen_associated_ops,
OpcodeId::SWAP4 => Swap::<4>::gen_associated_ops,
OpcodeId::SWAP5 => Swap::<5>::gen_associated_ops,
OpcodeId::SWAP6 => Swap::<6>::gen_associated_ops,
OpcodeId::SWAP7 => Swap::<7>::gen_associated_ops,
OpcodeId::SWAP8 => Swap::<8>::gen_associated_ops,
OpcodeId::SWAP9 => Swap::<9>::gen_associated_ops,
OpcodeId::SWAP10 => Swap::<10>::gen_associated_ops,
OpcodeId::SWAP11 => Swap::<11>::gen_associated_ops,
OpcodeId::SWAP12 => Swap::<12>::gen_associated_ops,
OpcodeId::SWAP13 => Swap::<13>::gen_associated_ops,
OpcodeId::SWAP14 => Swap::<14>::gen_associated_ops,
OpcodeId::SWAP15 => Swap::<15>::gen_associated_ops,
OpcodeId::SWAP16 => Swap::<16>::gen_associated_ops,
// OpcodeId::LOG0 => {},
// OpcodeId::LOG1 => {},
// OpcodeId::LOG2 => {},
// OpcodeId::LOG3 => {},
// OpcodeId::LOG4 => {},
// OpcodeId::CREATE => {},
// OpcodeId::CALL => {},
// OpcodeId::CALLCODE => {},
// OpcodeId::RETURN => {},
// OpcodeId::DELEGATECALL => {},
// OpcodeId::CREATE2 => {},
// OpcodeId::STATICCALL => {},
// OpcodeId::REVERT => {},
// OpcodeId::SELFDESTRUCT => {},
_ => unimplemented!(),
}
}
Expand Down
119 changes: 119 additions & 0 deletions bus-mapping/src/evm/opcodes/dup.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
use super::Opcode;
use crate::circuit_input_builder::CircuitInputStateRef;
use crate::eth_types::GethExecStep;
use crate::{
operation::{StackOp, RW},
Error,
};

/// Placeholder structure used to implement [`Opcode`] trait over it corresponding to the
/// `OpcodeId::DUP*` `OpcodeId`.
#[derive(Debug, Copy, Clone)]
pub(crate) struct Dup<const N: usize>;

impl<const N: usize> Opcode for Dup<N> {
fn gen_associated_ops(
state: &mut CircuitInputStateRef,
steps: &[GethExecStep],
) -> Result<(), Error> {
let step = &steps[0];

let stack_value_read = step.stack.nth_last(N - 1)?;
let stack_position = step.stack.nth_last_filled(N - 1);
state.push_op(StackOp::new(RW::READ, stack_position, stack_value_read));

state.push_op(StackOp::new(
RW::WRITE,
step.stack.last_filled().map(|a| a - 1),
stack_value_read,
));

Ok(())
}
}

#[cfg(test)]
mod dup_tests {
use super::*;
use crate::{
bytecode,
circuit_input_builder::{
CircuitInputBuilder, ExecStep, Transaction, TransactionContext,
},
evm::StackAddress,
mock, word,
};
use pretty_assertions::assert_eq;

#[test]
fn dup_opcode_impl() -> Result<(), Error> {
let code = bytecode! {
PUSH1(0x1)
PUSH1(0x2)
PUSH1(0x3)
#[start] // [1,2,3]
DUP1 // [1,2,3,3]
DUP3 // [1,2,3,3,2]
DUP5 // [1,2,3,3,2,1]
STOP
};

// Get the execution steps from the external tracer
let block =
mock::BlockData::new_single_tx_trace_code_at_start(&code).unwrap();

let mut builder = CircuitInputBuilder::new(
block.eth_block.clone(),
block.block_ctants.clone(),
);
builder.handle_tx(&block.eth_tx, &block.geth_trace).unwrap();

let mut test_builder = CircuitInputBuilder::new(
block.eth_block,
block.block_ctants.clone(),
);
let mut tx = Transaction::new(&block.eth_tx);
let mut tx_ctx = TransactionContext::new(&block.eth_tx);

// Generate steps corresponding to DUP1, DUP3, DUP5
for (i, word) in [word!("0x3"), word!("0x2"), word!("0x1")]
.iter()
.enumerate()
{
let mut step = ExecStep::new(
&block.geth_trace.struct_logs[i],
test_builder.block_ctx.gc,
);
let mut state_ref =
test_builder.state_ref(&mut tx, &mut tx_ctx, &mut step);

state_ref.push_op(StackOp::new(
RW::READ,
StackAddress(1024 - 3 + i),
*word,
));

state_ref.push_op(StackOp::new(
RW::WRITE,
StackAddress(1024 - 4 - i),
*word,
));

tx.steps_mut().push(step);
}

test_builder.block.txs_mut().push(tx);

// Compare first 3 steps bus mapping instance
for i in 0..3 {
assert_eq!(
builder.block.txs()[0].steps()[i].bus_mapping_instance,
test_builder.block.txs()[0].steps()[i].bus_mapping_instance
);
}
// Compare containers
assert_eq!(builder.block.container, test_builder.block.container);

Ok(())
}
}
19 changes: 19 additions & 0 deletions bus-mapping/src/evm/opcodes/jumpdest.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use super::Opcode;
use crate::circuit_input_builder::CircuitInputStateRef;
use crate::eth_types::GethExecStep;
use crate::Error;

/// Placeholder structure used to implement [`Opcode`] trait over it corresponding to the
/// [`OpcodeId::JUMPDEST`](crate::evm::OpcodeId::JUMPDEST) `OpcodeId`.
#[derive(Debug, Copy, Clone)]
pub(crate) struct Jumpdest;

impl Opcode for Jumpdest {
fn gen_associated_ops(
_state: &mut CircuitInputStateRef,
_steps: &[GethExecStep],
) -> Result<(), Error> {
// Jumpdest does not generate any operations
Ok(())
}
}
2 changes: 1 addition & 1 deletion bus-mapping/src/evm/opcodes/mload.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ use core::convert::TryInto;
pub(crate) struct Mload;

impl Opcode for Mload {
#[allow(unused_variables)]
fn gen_associated_ops(
state: &mut CircuitInputStateRef,
steps: &[GethExecStep],
Expand Down Expand Up @@ -67,6 +66,7 @@ mod mload_tests {
evm::StackAddress,
mock,
};
use pretty_assertions::assert_eq;

#[test]
fn mload_opcode_impl() -> Result<(), Error> {
Expand Down
Loading

0 comments on commit 83a6f39

Please sign in to comment.