diff --git a/evm/src/executor/abi/mod.rs b/evm/src/executor/abi/mod.rs index 3ba07ce1c0e5..efda7d8014c1 100644 --- a/evm/src/executor/abi/mod.rs +++ b/evm/src/executor/abi/mod.rs @@ -27,6 +27,7 @@ abigen!( ffi(string[])(bytes) breakpoint(string) + breakpoint(string,bool) roll(uint256) warp(uint256) diff --git a/evm/src/executor/inspector/cheatcodes/env.rs b/evm/src/executor/inspector/cheatcodes/env.rs index 490a9cdb6164..8f64e2aa9e59 100644 --- a/evm/src/executor/inspector/cheatcodes/env.rs +++ b/evm/src/executor/inspector/cheatcodes/env.rs @@ -192,7 +192,12 @@ fn get_recorded_logs(state: &mut Cheatcodes) -> Bytes { } /// Entry point of the breakpoint cheatcode. Adds the called breakpoint to the state. -fn add_breakpoint(state: &mut Cheatcodes, caller: Address, inner: &str) -> Result { +fn add_breakpoint( + state: &mut Cheatcodes, + caller: Address, + inner: &str, + add: bool, +) -> Result { let mut chars = inner.chars(); let point = chars.next(); @@ -209,7 +214,11 @@ fn add_breakpoint(state: &mut Cheatcodes, caller: Address, inner: &str) -> Resul } // add a breakpoint from the interpreter - state.breakpoints.insert(point, (caller, state.pc)); + if add { + state.breakpoints.insert(point, (caller, state.pc)); + } else { + state.breakpoints.remove(&point); + } Ok(Bytes::new()) } @@ -264,7 +273,8 @@ pub fn apply( .map_err(|err| err.encode_string())?; val.encode().into() } - HEVMCalls::Breakpoint(inner) => add_breakpoint(state, caller, &inner.0)?, + HEVMCalls::Breakpoint0(inner) => add_breakpoint(state, caller, &inner.0, true)?, + HEVMCalls::Breakpoint1(inner) => add_breakpoint(state, caller, &inner.0, inner.1)?, HEVMCalls::Etch(inner) => { let code = inner.1.clone(); trace!(address=?inner.0, code=?hex::encode(&code.0), "etch cheatcode"); diff --git a/ui/src/lib.rs b/ui/src/lib.rs index ae7bc5350c0b..c27d82ba9bbf 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -146,6 +146,7 @@ impl Tui { draw_memory: &mut DrawMemory, stack_labels: bool, mem_utf: bool, + help: bool, ) { let total_size = f.size(); if total_size.width < 225 { @@ -163,6 +164,7 @@ impl Tui { draw_memory, stack_labels, mem_utf, + help, ); } else { Tui::square_layout( @@ -179,6 +181,7 @@ impl Tui { draw_memory, stack_labels, mem_utf, + help, ); } } @@ -198,11 +201,16 @@ impl Tui { draw_memory: &mut DrawMemory, stack_labels: bool, mem_utf: bool, + help: bool, ) { let total_size = f.size(); + let h_height = if help { 4 } else { 0 }; + if let [app, footer] = Layout::default() + .constraints( + [Constraint::Ratio(100 - h_height, 100), Constraint::Ratio(h_height, 100)].as_ref(), + ) .direction(Direction::Vertical) - .constraints([Constraint::Ratio(98, 100), Constraint::Ratio(2, 100)].as_ref()) .split(total_size)[..] { if let [op_pane, stack_pane, memory_pane, src_pane] = Layout::default() @@ -218,7 +226,9 @@ impl Tui { ) .split(app)[..] { - Tui::draw_footer(f, footer); + if help { + Tui::draw_footer(f, footer); + } Tui::draw_src( f, address, @@ -253,7 +263,7 @@ impl Tui { } } else { panic!("unable to create footer / app") - } + }; } #[allow(clippy::too_many_arguments)] @@ -271,14 +281,18 @@ impl Tui { draw_memory: &mut DrawMemory, stack_labels: bool, mem_utf: bool, + help: bool, ) { let total_size = f.size(); + let h_height = if help { 4 } else { 0 }; // split in 2 vertically if let [app, footer] = Layout::default() .direction(Direction::Vertical) - .constraints([Constraint::Ratio(98, 100), Constraint::Ratio(2, 100)].as_ref()) + .constraints( + [Constraint::Ratio(100 - h_height, 100), Constraint::Ratio(h_height, 100)].as_ref(), + ) .split(total_size)[..] { if let [left_pane, right_pane] = Layout::default() @@ -297,7 +311,9 @@ impl Tui { .constraints([Constraint::Ratio(1, 4), Constraint::Ratio(3, 4)].as_ref()) .split(right_pane)[..] { - Tui::draw_footer(f, footer); + if help { + Tui::draw_footer(f, footer) + }; Tui::draw_src( f, address, @@ -348,15 +364,34 @@ impl Tui { fn draw_footer(f: &mut Frame, area: Rect) { let block_controls = Block::default(); + let dim = Style::default().add_modifier(Modifier::DIM); + + let _text_output = vec![ + Spans::from( + Span::styled( + "[q]: quit | [k/j]: prev/next op | [a/s]: prev/next jump | [c/C]: prev/next call | [g/G]: start/end", + dim, + ), + ), + Spans::from( + Span::styled( + "[t]: stack labels | [m]: memory decoding | [shift + j/k]: scroll stack | [ctrl + j/k]: scroll memory | [']: goto breakpoint | [h] close help", + dim, + ) + ) + ]; let text_output = Text::from(Span::styled( - "[q]: quit | [k/j]: prev/next op | [a/s]: prev/next jump | [c/C]: prev/next call | [g/G]: start/end | [t]: toggle stack labels | [m]: toggle memory decoding | [shift + j/k]: scroll stack | [ctrl + j/k]: scroll memory", - Style::default().add_modifier(Modifier::DIM) + "[q]: quit | [k/j]: prev/next op | [a/s]: prev/next jump | [c/C]: prev/next call | [g/G]: start/end\n +[t]: stack labels | [m]: memory decoding | [shift + j/k]: scroll stack | [ctrl + j/k]: scroll memory | [']: goto breakpoint", + Style::default().add_modifier(Modifier::DIM), )); + let paragraph = Paragraph::new(text_output) .block(block_controls) .alignment(Alignment::Center) .wrap(Wrap { trim: false }); + f.render_widget(paragraph, area); } @@ -1017,6 +1052,7 @@ impl Ui for Tui { let mut stack_labels = false; let mut mem_utf = false; + let mut help = false; // UI thread that manages drawing loop { if last_index != draw_memory.inner_call_index { @@ -1211,6 +1247,10 @@ impl Ui for Tui { KeyCode::Char('m') => { mem_utf = !mem_utf; } + // toggle help notice + KeyCode::Char('h') => { + help = !help; + } KeyCode::Char(other) => match other { '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' | '\'' => { self.key_buffer.push(other); @@ -1273,6 +1313,7 @@ impl Ui for Tui { &mut draw_memory, stack_labels, mem_utf, + help, ) })?; }