mirror of
https://github.com/logos-storage/plonky2.git
synced 2026-02-19 21:33:08 +00:00
Implement out of gas exception (#1328)
* Implement out of gas exception * Use gas constants in gas_cost_for_opcode * Remove comment
This commit is contained in:
parent
01f229a8e1
commit
0e63e66196
@ -24,8 +24,31 @@ global exception_jumptable:
|
||||
|
||||
|
||||
global exc_out_of_gas:
|
||||
// TODO
|
||||
%jump(fault_exception)
|
||||
// stack: trap_info
|
||||
%ctx_gas_limit
|
||||
// stack: gas_limit, trap_info
|
||||
DUP2 %shr_const(192)
|
||||
// stack: gas_used, gas_limit, trap_info
|
||||
DUP2 DUP2
|
||||
// stack: gas_used, gas_limit, gas_used, gas_limit, trap_info
|
||||
// If gas_used is already over the limit, panic. The exception should have
|
||||
// been raised earlier.
|
||||
GT %jumpi(panic)
|
||||
// stack: gas_used, gas_limit, trap_info
|
||||
DUP3 %opcode_from_exp_trap_info
|
||||
// stack: opcode, gas_used, gas_limit, trap_info
|
||||
%add_const(gas_cost_for_opcode)
|
||||
%mload_kernel_code
|
||||
// stack: gas_cost, gas_used, gas_limit, trap_info
|
||||
ADD
|
||||
// stack: new_gas_used, gas_limit, trap_info
|
||||
GT
|
||||
// stack: is_oog, trap_info
|
||||
SWAP1 POP
|
||||
// stack: is_oog
|
||||
%jumpi(fault_exception)
|
||||
// If we didn't jump, we shouldn't have raised the exception.
|
||||
PANIC
|
||||
|
||||
|
||||
global exc_invalid_opcode:
|
||||
@ -302,3 +325,110 @@ min_stack_len_for_opcode:
|
||||
BYTES 2 // 0xfd, REVERT
|
||||
BYTES 0 // 0xfe, invalid
|
||||
BYTES 1 // 0xff, SELFDESTRUCT
|
||||
|
||||
// A zero indicates either that the opcode is kernel-only,
|
||||
// or that it's handled with a syscall.
|
||||
gas_cost_for_opcode:
|
||||
BYTES 0 // 0x00, STOP
|
||||
BYTES @GAS_VERYLOW // 0x01, ADD
|
||||
BYTES @GAS_LOW // 0x02, MUL
|
||||
BYTES @GAS_VERYLOW // 0x03, SUB
|
||||
BYTES @GAS_LOW // 0x04, DIV
|
||||
BYTES @GAS_LOW // 0x05, SDIV
|
||||
BYTES @GAS_LOW // 0x06, MOD
|
||||
BYTES @GAS_LOW // 0x07, SMOD
|
||||
BYTES @GAS_MID // 0x08, ADDMOD
|
||||
BYTES @GAS_MID // 0x09, MULMOD
|
||||
BYTES 0 // 0x0a, EXP
|
||||
BYTES 0 // 0x0b, SIGNEXTEND
|
||||
%rep 4 // 0x0c-0x0f, invalid
|
||||
BYTES 0
|
||||
%endrep
|
||||
|
||||
BYTES @GAS_VERYLOW // 0x10, LT
|
||||
BYTES @GAS_VERYLOW // 0x11, GT
|
||||
BYTES @GAS_VERYLOW // 0x12, SLT
|
||||
BYTES @GAS_VERYLOW // 0x13, SGT
|
||||
BYTES @GAS_VERYLOW // 0x14, EQ
|
||||
BYTES @GAS_VERYLOW // 0x15, ISZERO
|
||||
BYTES @GAS_VERYLOW // 0x16, AND
|
||||
BYTES @GAS_VERYLOW // 0x17, OR
|
||||
BYTES @GAS_VERYLOW // 0x18, XOR
|
||||
BYTES @GAS_VERYLOW // 0x19, NOT
|
||||
BYTES @GAS_VERYLOW // 0x1a, BYTE
|
||||
BYTES @GAS_VERYLOW // 0x1b, SHL
|
||||
BYTES @GAS_VERYLOW // 0x1c, SHR
|
||||
BYTES @GAS_VERYLOW // 0x1d, SAR
|
||||
BYTES 0 // 0x1e, invalid
|
||||
BYTES 0 // 0x1f, invalid
|
||||
|
||||
BYTES 0 // 0x20, KECCAK256
|
||||
%rep 15 // 0x21-0x2f, invalid
|
||||
BYTES 0
|
||||
%endrep
|
||||
|
||||
%rep 25 //0x30-0x48, only syscalls
|
||||
BYTES 0
|
||||
%endrep
|
||||
|
||||
%rep 7 // 0x49-0x4f, invalid
|
||||
BYTES 0
|
||||
%endrep
|
||||
|
||||
BYTES @GAS_BASE // 0x50, POP
|
||||
BYTES 0 // 0x51, MLOAD
|
||||
BYTES 0 // 0x52, MSTORE
|
||||
BYTES 0 // 0x53, MSTORE8
|
||||
BYTES 0 // 0x54, SLOAD
|
||||
BYTES 0 // 0x55, SSTORE
|
||||
BYTES @GAS_MID // 0x56, JUMP
|
||||
BYTES @GAS_HIGH // 0x57, JUMPI
|
||||
BYTES @GAS_BASE // 0x58, PC
|
||||
BYTES 0 // 0x59, MSIZE
|
||||
BYTES 0 // 0x5a, GAS
|
||||
BYTES @GAS_JUMPDEST // 0x5b, JUMPDEST
|
||||
%rep 3 // 0x5c-0x5e, invalid
|
||||
BYTES 0
|
||||
%endrep
|
||||
|
||||
BYTES @GAS_BASE // 0x5f, PUSH0
|
||||
%rep 32 // 0x60-0x7f, PUSH1-PUSH32
|
||||
BYTES @GAS_VERYLOW
|
||||
%endrep
|
||||
|
||||
%rep 16 // 0x80-0x8f, DUP1-DUP16
|
||||
BYTES @GAS_VERYLOW
|
||||
%endrep
|
||||
|
||||
%rep 16 // 0x90-0x9f, SWAP1-SWAP16
|
||||
BYTES @GAS_VERYLOW
|
||||
%endrep
|
||||
|
||||
BYTES 0 // 0xa0, LOG0
|
||||
BYTES 0 // 0xa1, LOG1
|
||||
BYTES 0 // 0xa2, LOG2
|
||||
BYTES 0 // 0xa3, LOG3
|
||||
BYTES 0 // 0xa4, LOG4
|
||||
%rep 11 // 0xa5-0xaf, invalid
|
||||
BYTES 0
|
||||
%endrep
|
||||
|
||||
%rep 64 // 0xb0-0xef, invalid
|
||||
BYTES 0
|
||||
%endrep
|
||||
|
||||
BYTES 0 // 0xf0, CREATE
|
||||
BYTES 0 // 0xf1, CALL
|
||||
BYTES 0 // 0xf2, CALLCODE
|
||||
BYTES 0 // 0xf3, RETURN
|
||||
BYTES 0 // 0xf4, DELEGATECALL
|
||||
BYTES 0 // 0xf5, CREATE2
|
||||
%rep 4 // 0xf6-0xf9, invalid
|
||||
BYTES 0
|
||||
%endrep
|
||||
BYTES 0 // 0xfa, STATICCALL
|
||||
BYTES 0 // 0xfb, invalid
|
||||
BYTES 0 // 0xfc, invalid
|
||||
BYTES 0 // 0xfd, REVERT
|
||||
BYTES 0 // 0xfe, invalid
|
||||
BYTES 0 // 0xff, SELFDESTRUCT
|
||||
|
||||
@ -8,7 +8,7 @@ use keccak_hash::keccak;
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::ast::PushTarget;
|
||||
use super::ast::{BytesTarget, PushTarget};
|
||||
use crate::cpu::kernel::ast::Item::LocalLabelDeclaration;
|
||||
use crate::cpu::kernel::ast::{File, Item, StackReplacement};
|
||||
use crate::cpu::kernel::opcodes::{get_opcode, get_push_opcode};
|
||||
@ -277,6 +277,23 @@ fn inline_constants(body: Vec<Item>, constants: &HashMap<String, U256>) -> Vec<I
|
||||
.map(|item| {
|
||||
if let Item::Push(PushTarget::Constant(c)) = item {
|
||||
Item::Push(PushTarget::Literal(resolve_const(c)))
|
||||
} else if let Item::Bytes(targets) = item {
|
||||
let targets = targets
|
||||
.into_iter()
|
||||
.map(|target| {
|
||||
if let BytesTarget::Constant(c) = target {
|
||||
let c = resolve_const(c);
|
||||
assert!(
|
||||
c < U256::from(256),
|
||||
"Constant in a BYTES object should be a byte"
|
||||
);
|
||||
BytesTarget::Literal(c.byte(0))
|
||||
} else {
|
||||
target
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
Item::Bytes(targets)
|
||||
} else if let Item::StackManipulation(from, to) = item {
|
||||
let to = to
|
||||
.into_iter()
|
||||
@ -387,7 +404,14 @@ fn assemble_file(
|
||||
Item::StandardOp(opcode) => {
|
||||
code.push(get_opcode(&opcode));
|
||||
}
|
||||
Item::Bytes(bytes) => code.extend(bytes),
|
||||
Item::Bytes(targets) => {
|
||||
for target in targets {
|
||||
match target {
|
||||
BytesTarget::Literal(n) => code.push(n),
|
||||
BytesTarget::Constant(c) => panic!("Constant wasn't inlined: {c}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
Item::Jumptable(labels) => {
|
||||
for label in labels {
|
||||
let bytes = look_up_label(&label, &local_labels, global_labels);
|
||||
@ -507,7 +531,10 @@ mod tests {
|
||||
#[test]
|
||||
fn literal_bytes() {
|
||||
let file = File {
|
||||
body: vec![Item::Bytes(vec![0x12, 42]), Item::Bytes(vec![0xFE, 255])],
|
||||
body: vec![
|
||||
Item::Bytes(vec![BytesTarget::Literal(0x12), BytesTarget::Literal(42)]),
|
||||
Item::Bytes(vec![BytesTarget::Literal(0xFE), BytesTarget::Literal(255)]),
|
||||
],
|
||||
};
|
||||
let code = assemble(vec![file], HashMap::new(), false).code;
|
||||
assert_eq!(code, vec![0x12, 42, 0xfe, 255]);
|
||||
|
||||
@ -33,7 +33,7 @@ pub(crate) enum Item {
|
||||
/// Any opcode besides a PUSH opcode.
|
||||
StandardOp(String),
|
||||
/// Literal hex data; should contain an even number of hex chars.
|
||||
Bytes(Vec<u8>),
|
||||
Bytes(Vec<BytesTarget>),
|
||||
/// Creates a table of addresses from a list of labels.
|
||||
Jumptable(Vec<String>),
|
||||
}
|
||||
@ -75,3 +75,10 @@ pub(crate) enum PushTarget {
|
||||
MacroVar(String),
|
||||
Constant(String),
|
||||
}
|
||||
|
||||
/// The target of a `BYTES` item.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub(crate) enum BytesTarget {
|
||||
Literal(u8),
|
||||
Constant(String),
|
||||
}
|
||||
|
||||
@ -34,7 +34,8 @@ local_label_decl = ${ identifier ~ ":" }
|
||||
macro_label_decl = ${ "%%" ~ identifier ~ ":" }
|
||||
macro_label = ${ "%%" ~ identifier }
|
||||
|
||||
bytes_item = { ^"BYTES " ~ literal ~ ("," ~ literal)* }
|
||||
bytes_item = { ^"BYTES " ~ bytes_target ~ ("," ~ bytes_target)* }
|
||||
bytes_target = { literal | constant }
|
||||
jumptable_item = { ^"JUMPTABLE " ~ identifier ~ ("," ~ identifier)* }
|
||||
push_instruction = { ^"PUSH " ~ push_target }
|
||||
push_target = { literal | identifier | macro_label | variable | constant }
|
||||
|
||||
@ -4,7 +4,7 @@ use ethereum_types::U256;
|
||||
use pest::iterators::Pair;
|
||||
use pest::Parser;
|
||||
|
||||
use super::ast::StackPlaceholder;
|
||||
use super::ast::{BytesTarget, StackPlaceholder};
|
||||
use crate::cpu::kernel::ast::{File, Item, PushTarget, StackReplacement};
|
||||
|
||||
/// Parses EVM assembly code.
|
||||
@ -38,7 +38,7 @@ fn parse_item(item: Pair<Rule>) -> Item {
|
||||
Rule::macro_label_decl => {
|
||||
Item::MacroLabelDeclaration(item.into_inner().next().unwrap().as_str().into())
|
||||
}
|
||||
Rule::bytes_item => Item::Bytes(item.into_inner().map(parse_literal_u8).collect()),
|
||||
Rule::bytes_item => Item::Bytes(item.into_inner().map(parse_bytes_target).collect()),
|
||||
Rule::jumptable_item => {
|
||||
Item::Jumptable(item.into_inner().map(|i| i.as_str().into()).collect())
|
||||
}
|
||||
@ -167,6 +167,16 @@ fn parse_push_target(target: Pair<Rule>) -> PushTarget {
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_bytes_target(target: Pair<Rule>) -> BytesTarget {
|
||||
assert_eq!(target.as_rule(), Rule::bytes_target);
|
||||
let inner = target.into_inner().next().unwrap();
|
||||
match inner.as_rule() {
|
||||
Rule::literal => BytesTarget::Literal(parse_literal_u8(inner)),
|
||||
Rule::constant => BytesTarget::Constant(inner.into_inner().next().unwrap().as_str().into()),
|
||||
_ => panic!("Unexpected {:?}", inner.as_rule()),
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_literal_u8(literal: Pair<Rule>) -> u8 {
|
||||
let literal = literal.into_inner().next().unwrap();
|
||||
match literal.as_rule() {
|
||||
|
||||
@ -6,6 +6,7 @@ use super::memory::{MemoryOp, MemoryOpKind};
|
||||
use super::util::fill_channel_with_value;
|
||||
use crate::cpu::columns::CpuColumnsView;
|
||||
use crate::cpu::kernel::aggregator::KERNEL;
|
||||
use crate::cpu::kernel::constants::context_metadata::ContextMetadata;
|
||||
use crate::cpu::stack::{
|
||||
EQ_STACK_BEHAVIOR, IS_ZERO_STACK_BEHAVIOR, JUMPI_OP, JUMP_OP, STACK_BEHAVIORS,
|
||||
};
|
||||
@ -273,6 +274,23 @@ fn perform_op<F: Field>(
|
||||
|
||||
state.registers.gas_used += gas_to_charge(op);
|
||||
|
||||
let gas_limit_address = MemoryAddress {
|
||||
context: state.registers.context,
|
||||
segment: Segment::ContextMetadata as usize,
|
||||
virt: ContextMetadata::GasLimit as usize,
|
||||
};
|
||||
if !state.registers.is_kernel {
|
||||
let gas_limit = TryInto::<u64>::try_into(state.memory.get(gas_limit_address));
|
||||
match gas_limit {
|
||||
Ok(limit) => {
|
||||
if state.registers.gas_used > limit {
|
||||
return Err(ProgramError::OutOfGas);
|
||||
}
|
||||
}
|
||||
Err(_) => return Err(ProgramError::IntegerTooLarge),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user