diff --git a/fvm/src/call_manager/default.rs b/fvm/src/call_manager/default.rs index 33ce27d3f..3eab1420a 100644 --- a/fvm/src/call_manager/default.rs +++ b/fvm/src/call_manager/default.rs @@ -183,18 +183,20 @@ where K: Kernel, { if self.machine.context().tracing { - self.trace(ExecutionEvent::Call { - from, - to, - entrypoint, - params: params.as_ref().map(Into::into), - value: value.clone(), - gas_limit: std::cmp::min( - gas_limit.unwrap_or(Gas::from_milligas(u64::MAX)).round_up(), - self.gas_tracker.gas_available().round_up(), - ), - read_only, - }); + if let Entrypoint::Invoke(method) = &entrypoint { + self.trace(ExecutionEvent::Call { + from, + to, + method: *method, + params: params.as_ref().map(Into::into), + value: value.clone(), + gas_limit: std::cmp::min( + gas_limit.unwrap_or(Gas::from_milligas(u64::MAX)).round_up(), + self.gas_tracker.gas_available().round_up(), + ), + read_only, + }); + } } // If a specific gas limit has been requested, push a new limit into the gas tracker. @@ -222,7 +224,7 @@ where }) } - if self.machine.context().tracing { + if self.machine.context().tracing && matches!(entrypoint, Entrypoint::Invoke(_)) { self.trace(match &result { Ok(InvocationResult { exit_code, value }) => { ExecutionEvent::CallReturn(*exit_code, value.as_ref().map(Into::into)) @@ -578,7 +580,7 @@ where self.call_actor_resolved::( system_actor::SYSTEM_ACTOR_ID, id, - Entrypoint::Invoke(fvm_shared::METHOD_CONSTRUCTOR), + Entrypoint::ImplicitConstructor, Some(Block::new(CBOR, params, Vec::new())), &TokenAmount::zero(), false, @@ -660,8 +662,17 @@ where .get_actor(to)? .ok_or_else(|| syscall_error!(NotFound; "actor does not exist: {}", to))?; - if self.machine.context().tracing { - self.trace(ExecutionEvent::InvokeActor(state.code)); + // We're only tracing explicit "invokes" (no upgrades or implicit constructions, for now) as + // we want to be able to pair the invoke with another event in the trace. I.e. call -> + // invoke, upgrade -> invoke, construct -> invoke. + // + // Once we add tracing support for upgrades, we can start recording those actor invocations + // as well. + if self.machine.context().tracing && matches!(entrypoint, Entrypoint::Invoke(_)) { + self.trace(ExecutionEvent::InvokeActor { + id: to, + state: state.clone(), + }); } // Transfer, if necessary. diff --git a/fvm/src/call_manager/mod.rs b/fvm/src/call_manager/mod.rs index 680c8ecda..b8d217e39 100644 --- a/fvm/src/call_manager/mod.rs +++ b/fvm/src/call_manager/mod.rs @@ -6,7 +6,7 @@ use fvm_shared::address::Address; use fvm_shared::econ::TokenAmount; use fvm_shared::error::ExitCode; use fvm_shared::upgrade::UpgradeInfo; -use fvm_shared::{ActorID, MethodNum}; +use fvm_shared::{ActorID, MethodNum, METHOD_CONSTRUCTOR}; use crate::engine::Engine; use crate::gas::{Gas, GasCharge, GasTimer, GasTracker, PriceList}; @@ -205,7 +205,11 @@ pub struct FinishRet { #[derive(Clone, Debug, Copy)] pub enum Entrypoint { + /// Implicitly invoke a constructor. We keep this separate for better tracing. + ImplicitConstructor, + /// Invoke a method. Invoke(MethodNum), + /// Upgrade to a new actor code CID. Upgrade(UpgradeInfo), } @@ -217,6 +221,7 @@ const METHOD_UPGRADE: MethodNum = 932083; impl std::fmt::Display for Entrypoint { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { + Entrypoint::ImplicitConstructor => write!(f, "implicit_constructor"), Entrypoint::Invoke(method) => write!(f, "invoke({})", method), Entrypoint::Upgrade(_) => write!(f, "upgrade"), } @@ -226,6 +231,7 @@ impl std::fmt::Display for Entrypoint { impl Entrypoint { fn method_num(&self) -> MethodNum { match self { + Entrypoint::ImplicitConstructor => METHOD_CONSTRUCTOR, Entrypoint::Invoke(num) => *num, Entrypoint::Upgrade(_) => METHOD_UPGRADE, } @@ -233,13 +239,14 @@ impl Entrypoint { fn func_name(&self) -> &'static str { match self { - Entrypoint::Invoke(_) => INVOKE_FUNC_NAME, + Entrypoint::ImplicitConstructor | Entrypoint::Invoke(_) => INVOKE_FUNC_NAME, Entrypoint::Upgrade(_) => UPGRADE_FUNC_NAME, } } fn invokes(&self, method: MethodNum) -> bool { match self { + Entrypoint::ImplicitConstructor => method == METHOD_CONSTRUCTOR, Entrypoint::Invoke(num) => *num == method, Entrypoint::Upgrade(_) => false, } @@ -247,7 +254,7 @@ impl Entrypoint { fn into_params(self, br: &mut BlockRegistry) -> Result> { match self { - Entrypoint::Invoke(_) => Ok(Vec::new()), + Entrypoint::ImplicitConstructor | Entrypoint::Invoke(_) => Ok(Vec::new()), Entrypoint::Upgrade(ui) => { let ui_params = to_vec(&ui) .or_fatal() diff --git a/fvm/src/trace/mod.rs b/fvm/src/trace/mod.rs index 888589c89..30f5c03c2 100644 --- a/fvm/src/trace/mod.rs +++ b/fvm/src/trace/mod.rs @@ -1,13 +1,12 @@ -use cid::Cid; // Copyright 2021-2023 Protocol Labs // SPDX-License-Identifier: Apache-2.0, MIT use fvm_ipld_encoding::ipld_block::IpldBlock; use fvm_shared::address::Address; use fvm_shared::econ::TokenAmount; use fvm_shared::error::ExitCode; -use fvm_shared::ActorID; +use fvm_shared::state::ActorState; +use fvm_shared::{ActorID, MethodNum}; -use crate::call_manager::Entrypoint; use crate::gas::GasCharge; use crate::kernel::SyscallError; @@ -26,7 +25,7 @@ pub enum ExecutionEvent { Call { from: ActorID, to: Address, - entrypoint: Entrypoint, + method: MethodNum, params: Option, value: TokenAmount, gas_limit: u64, @@ -34,6 +33,9 @@ pub enum ExecutionEvent { }, CallReturn(ExitCode, Option), CallError(SyscallError), - /// Emitted every time we successfully invoke an actor - InvokeActor(Cid), + /// Emitted every time an actor is successfully invoked. + InvokeActor { + id: ActorID, + state: ActorState, + }, }