Skip to content
This repository was archived by the owner on Apr 18, 2025. It is now read-only.
Merged
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
4 changes: 3 additions & 1 deletion bus-mapping/src/evm/opcodes.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//! Definition of each opcode of the EVM.
mod coinbase;
mod dup;
pub mod ids;
mod jump;
Expand All @@ -22,6 +23,7 @@ use ids::OpcodeId;
use log::warn;

use self::push::Push;
use coinbase::Coinbase;
use dup::Dup;
use jump::Jump;
use jumpdest::Jumpdest;
Expand Down Expand Up @@ -110,7 +112,7 @@ impl OpcodeId {
// OpcodeId::RETURNDATACOPY => {},
// OpcodeId::EXTCODEHASH => {},
// OpcodeId::BLOCKHASH => {},
// OpcodeId::COINBASE => {},
OpcodeId::COINBASE => Coinbase::gen_associated_ops,
// OpcodeId::TIMESTAMP => {},
// OpcodeId::NUMBER => {},
// OpcodeId::DIFFICULTY => {},
Expand Down
91 changes: 91 additions & 0 deletions bus-mapping/src/evm/opcodes/coinbase.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
use super::Opcode;
use crate::circuit_input_builder::CircuitInputStateRef;
use crate::eth_types::GethExecStep;
use crate::{operation::RW, Error};

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

impl Opcode for Coinbase {
fn gen_associated_ops(
state: &mut CircuitInputStateRef,
steps: &[GethExecStep],
) -> Result<(), Error> {
let step = &steps[0];
// Get value result from next step and do stack write
let value = steps[1].stack.last()?;
state.push_stack_op(
RW::WRITE,
step.stack.last_filled().map(|a| a - 1),
value,
);

Ok(())
}
}

#[cfg(test)]
mod coinbase_tests {
use super::*;
use crate::{
bytecode,
circuit_input_builder::{ExecStep, TransactionContext},
eth_types::ToWord,
evm::StackAddress,
mock,
};
use pretty_assertions::assert_eq;

#[test]
fn coinbase_opcode_impl() -> Result<(), Error> {
let code = bytecode! {
#[start]
COINBASE
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 = block.new_circuit_input_builder();
builder.handle_tx(&block.eth_tx, &block.geth_trace).unwrap();

let mut test_builder = block.new_circuit_input_builder();
let mut tx = test_builder.new_tx(&block.eth_tx).unwrap();
let mut tx_ctx = TransactionContext::new(&block.eth_tx);

// Generate step corresponding to COINBASE
let mut step = ExecStep::new(
&block.geth_trace.struct_logs[0],
0,
test_builder.block_ctx.rwc,
0,
);
let mut state_ref =
test_builder.state_ref(&mut tx, &mut tx_ctx, &mut step);

// Add the last Stack write
state_ref.push_stack_op(
RW::WRITE,
StackAddress::from(1024 - 1),
block.ctants.coinbase.to_word(),
);

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

// Compare first step bus mapping instance
assert_eq!(
builder.block.txs()[0].steps()[0].bus_mapping_instance,
test_builder.block.txs()[0].steps()[0].bus_mapping_instance,
);

// Compare containers
assert_eq!(builder.block.container, test_builder.block.container);

Ok(())
}
}