Skip to content

Commit 58d2465

Browse files
committed
fix: robustify trace reordering
This gets rid of some edge cases and avoids some iteration methods that are hard to reason about (`take_while` should die).
1 parent 8af9f29 commit 58d2465

File tree

1 file changed

+65
-66
lines changed

1 file changed

+65
-66
lines changed

rust/src/fvm/machine.rs

Lines changed: 65 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,12 @@ use std::convert::{TryFrom, TryInto};
44
use anyhow::{anyhow, Context};
55
use cid::Cid;
66
use fvm3::executor::ApplyKind as ApplyKind3;
7-
use fvm3::gas::{Gas, GasCharge};
7+
use fvm3::gas::GasCharge;
88
use fvm3::trace::ExecutionEvent;
9+
use fvm3_ipld_encoding::ipld_block::IpldBlock;
910
use fvm3_ipld_encoding::tuple::{Deserialize_tuple, Serialize_tuple};
1011
use fvm3_ipld_encoding::{to_vec, CborStore, RawBytes};
1112
use fvm3_shared::address::Address;
12-
use num_traits::Zero;
1313

1414
use fvm3_shared::error::{ErrorNumber, ExitCode};
1515
use fvm3_shared::receipt::Receipt;
@@ -205,24 +205,38 @@ fn fvm_machine_execute_message(
205205

206206
let exec_trace = if !apply_ret.exec_trace.is_empty() {
207207
let mut trace_iter = apply_ret.exec_trace.into_iter();
208-
let initial_gas_charges: Vec<GasCharge> = trace_iter
209-
.clone()
210-
.take_while(|e| matches!(e, &ExecutionEvent::GasCharge(_)))
211-
.map(|e| match e {
212-
ExecutionEvent::GasCharge(gc) => gc,
213-
_ => GasCharge::new("none", Gas::zero(), Gas::zero()),
214-
})
215-
.collect();
216-
match trace_iter.nth(initial_gas_charges.len()) {
217-
Some(c) => build_lotus_trace(initial_gas_charges, c, &mut trace_iter)
218-
.ok()
219-
.and_then(|t| to_vec(&t).ok())
220-
.map(|trace| trace.into_boxed_slice().into()),
221-
_ => None,
208+
let mut initial_gas_charges = Vec::new();
209+
loop {
210+
match trace_iter.next() {
211+
Some(gc @ ExecutionEvent::GasCharge(_)) => initial_gas_charges.push(gc),
212+
Some(ExecutionEvent::Call {
213+
from,
214+
to,
215+
method,
216+
params,
217+
value,
218+
}) => {
219+
break build_lotus_trace(
220+
from,
221+
to,
222+
method,
223+
params,
224+
value,
225+
&mut initial_gas_charges.into_iter().chain(&mut trace_iter),
226+
)
227+
.ok()
228+
}
229+
// Skip anything unexpected.
230+
Some(_) => {}
231+
// Return none if we don't even have a call.
232+
None => break None,
233+
}
222234
}
223235
} else {
224236
None
225-
};
237+
}
238+
.and_then(|t| to_vec(&t).ok())
239+
.map(|trace| trace.into_boxed_slice().into());
226240

227241
let failure_info = apply_ret
228242
.failure_info
@@ -343,66 +357,48 @@ pub struct LotusReceipt {
343357
}
344358

345359
fn build_lotus_trace(
346-
initial_gas_charges: Vec<GasCharge>,
347-
new_call: ExecutionEvent,
360+
from: u64,
361+
to: Address,
362+
method: u64,
363+
params: Option<IpldBlock>,
364+
value: TokenAmount,
348365
trace_iter: &mut impl Iterator<Item = ExecutionEvent>,
349366
) -> anyhow::Result<LotusTrace> {
350367
let mut new_trace = LotusTrace {
351-
msg: match new_call {
352-
ExecutionEvent::Call {
353-
from,
354-
to,
355-
method,
356-
params,
357-
value,
358-
} => Message {
359-
version: 0,
360-
from: Address::new_id(from),
361-
to,
362-
value,
363-
sequence: 0,
364-
method_num: method,
365-
params: params.map(|b| b.data).unwrap_or_default().into(),
366-
gas_limit: 0,
367-
gas_fee_cap: TokenAmount::default(),
368-
gas_premium: TokenAmount::default(),
369-
},
370-
_ => {
371-
return Err(anyhow!("expected ExecutionEvent of type Call"));
372-
}
368+
msg: Message {
369+
version: 0,
370+
from: Address::new_id(from),
371+
to,
372+
value,
373+
sequence: 0,
374+
method_num: method,
375+
params: params.map(|b| b.data).unwrap_or_default().into(),
376+
gas_limit: 0,
377+
gas_fee_cap: TokenAmount::default(),
378+
gas_premium: TokenAmount::default(),
373379
},
374380
msg_receipt: LotusReceipt {
375381
exit_code: ExitCode::OK,
376382
return_data: RawBytes::default(),
377383
gas_used: 0,
378384
},
379385
error: String::new(),
380-
gas_charges: initial_gas_charges
381-
.iter()
382-
.cloned()
383-
.map(
384-
|GasCharge {
385-
name,
386-
compute_gas,
387-
other_gas,
388-
elapsed: _, // TODO: thread timing through to lotus.
389-
}| LotusGasCharge {
390-
name,
391-
total_gas: (compute_gas + other_gas).round_up(),
392-
compute_gas: compute_gas.round_up(),
393-
other_gas: other_gas.round_up(),
394-
},
395-
)
396-
.collect(),
386+
gas_charges: vec![],
397387
subcalls: vec![],
398388
};
399389

400390
while let Some(trace) = trace_iter.next() {
401391
match trace {
402-
ExecutionEvent::Call { .. } => {
403-
new_trace
404-
.subcalls
405-
.push(build_lotus_trace(vec![], trace, trace_iter)?);
392+
ExecutionEvent::Call {
393+
from,
394+
to,
395+
method,
396+
params,
397+
value,
398+
} => {
399+
new_trace.subcalls.push(build_lotus_trace(
400+
from, to, method, params, value, trace_iter,
401+
)?);
406402
}
407403
ExecutionEvent::CallReturn(exit_code, return_data) => {
408404
new_trace.msg_receipt = LotusReceipt {
@@ -472,8 +468,9 @@ mod test {
472468
};
473469
let return_result =
474470
ExecutionEvent::CallError(SyscallError::new(IllegalArgument, "illegal"));
471+
let initial_gas_charge = GasCharge::new("gas_test", Gas::new(1), Gas::new(2));
475472
let trace = vec![
476-
call_event.clone(),
473+
ExecutionEvent::GasCharge(initial_gas_charge.clone()),
477474
call_event.clone(),
478475
return_result.clone(),
479476
call_event.clone(),
@@ -485,10 +482,12 @@ mod test {
485482

486483
let mut trace_iter = trace.into_iter();
487484

488-
let initial_gas_charge = GasCharge::new("gas_test", Gas::new(1), Gas::new(2));
489485
let lotus_trace = build_lotus_trace(
490-
vec![initial_gas_charge.clone()],
491-
trace_iter.next().unwrap(),
486+
0,
487+
Address::new_id(0),
488+
0,
489+
None,
490+
TokenAmount::default(),
492491
&mut trace_iter,
493492
)
494493
.unwrap();

0 commit comments

Comments
 (0)