Skip to content

(WIP) migrate move_vm_stack to TraceState#14

Open
lbr77 wants to merge 15 commits intoBitsLabSec:v1.65.2-pendingfrom
lbr77:master
Open

(WIP) migrate move_vm_stack to TraceState#14
lbr77 wants to merge 15 commits intoBitsLabSec:v1.65.2-pendingfrom
lbr77:master

Conversation

@lbr77
Copy link
Contributor

@lbr77 lbr77 commented Jan 28, 2026

No description provided.

Copilot AI review requested due to automatic review settings January 28, 2026 14:05
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR is a WIP refactor to migrate tracing/oracle logic away from move_vm_stack::Stack by introducing a TraceState that reconstructs operand/locals/global state from the trace event stream, and by adding a wrapper tracer that can enrich instruction events with module-derived metadata.

Changes:

  • Introduce TraceState to track operand stack, locals, and loaded global state from TraceEvents, and plumb it through tracer/oracle interfaces.
  • Add NotifierTracer (+ ModuleProvider) to wrap a notifier-style tracer and synthesize BeforeInstruction events with extra metadata (e.g., pack/unpack field counts).
  • Update fuzz tracer + Sui oracles to consume TraceState instead of move_vm_stack::Stack, and adjust workspace dependencies (notably move-vm-runtime) accordingly.

Reviewed changes

Copilot reviewed 18 out of 19 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
crates/movy-replay/src/tracer/tree.rs Removes Stack import; uses fully-qualified stack type in tracer interface.
crates/movy-replay/src/tracer/trace.rs Adds TraceState state machine for reconstructing VM state from trace events.
crates/movy-replay/src/tracer/oracle.rs Changes oracle callback signature to accept TraceState instead of Stack.
crates/movy-replay/src/tracer/op.rs Adds conversions from TraceValue/SerializableMoveValue into Magic for logging.
crates/movy-replay/src/tracer/mod.rs Exposes new trace module.
crates/movy-replay/src/tracer/fuzz.rs Refactors fuzz tracer to maintain TraceState and implement notifier-style tracing.
crates/movy-replay/src/tracer/concolic.rs Refactors concolic execution to use TraceState operand stack instead of Stack.
crates/movy-replay/src/lib.rs Exposes new event module.
crates/movy-replay/src/event.rs Adds NotifierTracer/ModuleProvider and synthesized BeforeInstruction events with extra info.
crates/movy-fuzz/src/oracles/sui/typed_bug.rs Updates oracle signature to accept TraceState.
crates/movy-fuzz/src/oracles/sui/type_conversion.rs Updates oracle to use TraceState.operand_stack for cast checks.
crates/movy-fuzz/src/oracles/sui/proceeds.rs Updates oracle signature to accept TraceState.
crates/movy-fuzz/src/oracles/sui/precision_loss.rs Updates oracle signature to accept TraceState.
crates/movy-fuzz/src/oracles/sui/overflow.rs Updates oracle to use TraceState.operand_stack and TraceValue.
crates/movy-fuzz/src/oracles/sui/infinite_loop.rs Updates oracle signature to accept TraceState.
crates/movy-fuzz/src/oracles/sui/bool_judgement.rs Updates oracle signature to accept TraceState.
crates/movy-fuzz/src/executor.rs Wraps fuzz tracer with NotifierTracer and provides on-chain module loading for metadata enrichment.
Cargo.toml Enables pprof frame pointers and switches move-vm-runtime git branch.
Cargo.lock Updates lockfile to reflect new dependency graph.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


match event {
TraceEvent::BeforeInstruction { .. } => {
return;
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NotifierTracer::notify returns early on TraceEvent::BeforeInstruction, so notify_event is never called for those events. This means any notifier logic that depends on real BeforeInstruction events (including any richer data they may carry) is skipped. Consider forwarding these events to notify_event as well, or explicitly preferring the real BeforeInstruction over a synthesized one (and only synthesizing when missing).

Suggested change
return;
if let Err(e) = self.notifier.notify_event(event) {
log::error!(
"NotifierTracer: failed to notify BeforeInstruction: {:?}",
e
);
}

Copilot uses AI. Check for mistakes.
Comment on lines 64 to 69
let SimplifiedMoveStruct { type_, .. } = data;
let mut bytes = type_.address.to_vec();
bytes.extend_from_slice(type_.module.as_bytes());
bytes.extend_from_slice(type_.name.as_bytes());
Ok(Self::Bytes(bytes))
}
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the Struct case, the byte representation is built by concatenating address || module || name without length-prefixing or separators, which can lead to ambiguous encodings (different (module,name) pairs producing the same bytes). If this is meant to be a stable identifier (it’s used in an Eq/Ord/Hash type), add separators/length-prefixes (or use a structured serialization) to prevent collisions.

Suggested change
let SimplifiedMoveStruct { type_, .. } = data;
let mut bytes = type_.address.to_vec();
bytes.extend_from_slice(type_.module.as_bytes());
bytes.extend_from_slice(type_.name.as_bytes());
Ok(Self::Bytes(bytes))
}
let SimplifiedMoveStruct { type_, .. } = data;
let address_bytes = type_.address.to_vec();
let module_bytes = type_.module.as_bytes();
let name_bytes = type_.name.as_bytes();
// Encode as: address || len(module) || module || len(name) || name
// where lengths are u16 big-endian to avoid ambiguous encodings.
let mut bytes = Vec::with_capacity(
address_bytes.len()
+ 2 + module_bytes.len()
+ 2 + name_bytes.len(),
);
bytes.extend_from_slice(&address_bytes);
bytes.extend_from_slice(&(module_bytes.len() as u16).to_be_bytes());
bytes.extend_from_slice(module_bytes);
bytes.extend_from_slice(&(name_bytes.len() as u16).to_be_bytes());
bytes.extend_from_slice(name_bytes);
Ok(Self::Bytes(bytes))
}

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +11
//! and open/close frame event that is has built up.
//!
//! The memory tracer is useful for debugging, and as an example of how to build up this
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling/grammar: “that is has built up” reads incorrect in the doc comment.

Suggested change
//! and open/close frame event that is has built up.
//!
//! The memory tracer is useful for debugging, and as an example of how to build up this
//! and open/close frame events that it has built up.
//!
//! The memory tracer is useful for debugging, and as an example of how to build up this

Copilot uses AI. Check for mistakes.
self.loaded_state.insert(*id, snapshot.clone());
}
},
// External events are treated opaqeuly
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling: “opaqeuly” should be “opaquely”.

Suggested change
// External events are treated opaqeuly
// External events are treated opaquely

Copilot uses AI. Check for mistakes.
Comment on lines 213 to 219
Some(TraceEvent::BeforeInstruction {
pc: *pc,
instruction: instruction.clone(),
extra,
type_parameters: vec![],
gas_left: 0,
})
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create_before_instruction synthesizes a BeforeInstruction with type_parameters: vec![] and gas_left: 0, discarding whatever information is available at runtime. If downstream logic relies on these fields, this will produce incorrect traces. Prefer copying these fields from the original event/context when possible, or make the synthetic values explicit (e.g., None/"unknown") if the format supports it.

Copilot uses AI. Check for mistakes.
bytes.extend_from_slice(type_.name.as_bytes());
Ok(Self::Bytes(bytes))
}
_ => Err(eyre!("TraceValue is not an integer {:?}", value).into()),
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The error message for unsupported values says “TraceValue is not an integer …”, but this conversion is operating on SerializableMoveValue and also supports non-integer cases like Address/Struct. Consider updating the message to reflect what’s actually unsupported (e.g., “unsupported value for Magic conversion”).

Suggested change
_ => Err(eyre!("TraceValue is not an integer {:?}", value).into()),
_ => Err(eyre!("unsupported SerializableMoveValue for Magic conversion: {:?}", value).into()),

Copilot uses AI. Check for mistakes.
Comment on lines +317 to +319
// if self.stack.len() != stack.len() && stack.is_empty() {
// self.stack.clear();
// }
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There’s commented-out logic for stack resynchronization (// if self.stack.len() != stack.len() ...) left in notify_event. Please either remove this dead code or reintroduce it behind a clear condition/flag; leaving commented blocks makes the concolic stack invariants harder to reason about.

Suggested change
// if self.stack.len() != stack.len() && stack.is_empty() {
// self.stack.clear();
// }

Copilot uses AI. Check for mistakes.
Comment on lines +8 to +12
//! The memory tracer then emits `External` events with the current VM state for every instruction,
//! and open/close frame event that is has built up.
//!
//! The memory tracer is useful for debugging, and as an example of how to build up this
//! state for more advanced analysis and also using the custom tracing trait.
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The module-level docs say this tracer “emits External events with the current VM state for every instruction, and open/close frame event”, but the Tracer impl only updates internal state and never writes/emits any new events. Either implement the described emission behavior, or update the docs to reflect the current (state-only) behavior to avoid misleading consumers.

Copilot uses AI. Check for mistakes.
Comment on lines 148 to 150
fn notify(&mut self, event: &TraceEvent, mut write: &mut Writer<'_>, _stack: Option<&Stack>) {
self.apply_event(event);
// no emit for
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TraceState::notify has an unused write parameter and a dangling/incomplete comment (// no emit for). Rename the param to _writer (or use it) and either complete or remove the comment to keep the implementation warning-free and clear.

Suggested change
fn notify(&mut self, event: &TraceEvent, mut write: &mut Writer<'_>, _stack: Option<&Stack>) {
self.apply_event(event);
// no emit for
fn notify(&mut self, event: &TraceEvent, _writer: &mut Writer<'_>, _stack: Option<&Stack>) {
self.apply_event(event);

Copilot uses AI. Check for mistakes.
@wtdcode wtdcode self-assigned this Jan 29, 2026
@lbr77 lbr77 closed this Feb 7, 2026
@lbr77 lbr77 reopened this Feb 11, 2026
@lbr77 lbr77 changed the base branch from master to v1.65.2-pending February 11, 2026 10:23
@lbr77 lbr77 force-pushed the master branch 2 times, most recently from 950787e to e009a75 Compare February 12, 2026 05:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants