Skip to content

Commit

Permalink
perf: add addition fields in json output
Browse files Browse the repository at this point in the history
- exit_code
- vm_success
- gas_used
- message.state_init
  • Loading branch information
ilyar committed Oct 19, 2024
1 parent 619071b commit 703d64f
Show file tree
Hide file tree
Showing 4 changed files with 115 additions and 33 deletions.
12 changes: 6 additions & 6 deletions tvm_debugger/src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ pub(crate) fn decode_actions(
.map_err(|e| anyhow::format_err!("SliceData::load_cell: {e}"))?,
)
.map_err(|e| anyhow::format_err!("OutActions::construct_from: {e}"))?;
res.push("Output actions:\n----------------".to_string());
res.log("Output actions:\n----------------".to_string());
let mut created_lt = 1;
for act in actions {
match act {
Expand All @@ -63,7 +63,7 @@ pub(crate) fn decode_actions(
created_lt += 1;
}
res.add_out_message(out_msg.clone());
res.push(format!("Action(SendMsg):\n{}", msg_printer(&out_msg)?));
res.log(format!("Action(SendMsg):\n{}", msg_printer(&out_msg)?));
if let Some(b) = out_msg.body() {
if abi_file.is_some() && function_name.is_some() {
decode_body(
Expand All @@ -77,16 +77,16 @@ pub(crate) fn decode_actions(
}
}
OutAction::SetCode { new_code: code } => {
res.push("Action(SetCode)".to_string());
res.log("Action(SetCode)".to_string());
state.code = Some(code);
}
OutAction::ReserveCurrency { .. } => {
res.push("Action(ReserveCurrency)".to_string());
res.log("Action(ReserveCurrency)".to_string());
}
OutAction::ChangeLibrary { .. } => {
res.push("Action(ChangeLibrary)".to_string());
res.log("Action(ChangeLibrary)".to_string());
}
_ => res.push("Action(Unknown)".to_string()),
_ => res.log("Action(Unknown)".to_string()),
};
}
}
Expand Down
20 changes: 9 additions & 11 deletions tvm_debugger/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,21 +57,19 @@ pub(crate) fn execute(args: &Args, res: &mut ExecutionResult) -> anyhow::Result<

let exit_code = engine.execute().unwrap_or_else(|error| match tvm_exception(error) {
Ok(exception) => {
println!("Unhandled exception: {}", exception);
res.log(format!("Unhandled exception: {}", exception));
exception.exception_or_custom_code()
}
_ => -1,
});

let is_vm_success = engine.get_committed_state().is_committed();
res.push(format!("TVM terminated with exit code {}", exit_code));
res.push(format!("Computing phase is success: {}", is_vm_success));
res.push(format!("Gas used: {}", engine.get_gas().get_gas_used()));
res.push("".to_string());
res.push(format!("{}", engine.dump_stack("Post-execution stack state", false)));
res.push(format!("{}", engine.dump_ctrls(false)));
res.exit_code(exit_code);
res.vm_success(engine.get_committed_state().is_committed());
res.gas_used(engine.get_gas().get_gas_used());
res.log(format!("{}", engine.dump_stack("Post-execution stack state", false)));
res.log(format!("{}", engine.dump_ctrls(false)));

if is_vm_success {
if res.is_vm_success {
decode_actions(engine.get_actions(), &mut contract_state_init, args, res)?;

contract_state_init.data = match engine.get_committed_state().get_root() {
Expand All @@ -82,10 +80,10 @@ pub(crate) fn execute(args: &Args, res: &mut ExecutionResult) -> anyhow::Result<
.write_to_file(&args.input_file)
.map_err(|e| anyhow::format_err!("Failed to save state init after execution: {e}"))?;

res.push("Contract persistent data updated".to_string());
res.log("Contract persistent data updated".to_string());
}

res.push("EXECUTION COMPLETED".to_string());
res.log("EXECUTION COMPLETED".to_string());

Ok(())
}
Expand Down
57 changes: 56 additions & 1 deletion tvm_debugger/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,61 @@ fn main() -> anyhow::Result<()> {
let args: Args = Args::parse();
let mut res: ExecutionResult = ExecutionResult::new(args.json);
execute(&args, &mut res)?;
res.print();
println!("{}", res.output());
Ok(())
}

#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
use std::fs;
use std::path::PathBuf;

fn create_temp_contract_file() -> PathBuf {
let temp_path = PathBuf::from("tests/temp_contract.tvc");
fs::copy("tests/contract/contract.tvc", &temp_path).expect("Failed to copy contract file");
temp_path
}

fn cleanup_temp_contract_file(temp_path: &PathBuf) {
fs::remove_file(temp_path).expect("Failed to delete temporary contract file");
}

fn default_args(input_file: PathBuf, func: &str) -> Args {
Args {
input_file,
abi_file: Some(PathBuf::from("tests/contract/contract.abi.json")),
abi_header: None,
function_name: Some(func.to_string()),
call_parameters: None,
address: None,
sign: None,
internal: false,
message_value: None,
message_ecc: None,
message_source: None,
decode_out_messages: false,
json: true,
trace: false,
}
}

#[test]
fn test_valid_input() {
let temp = create_temp_contract_file();
let args = &default_args(temp.clone(), "counter");
let mut res: ExecutionResult = ExecutionResult::new(args.json);
let result = execute(args, &mut res);
assert!(result.is_ok());
let actual = res.to_json();
let response = json!({
"counter": "0x0000000000000000000000000000000000000000000000000000000000000000".to_string(),
});
assert_eq!(actual["exit_code"], 0i32);
assert_eq!(actual["vm_success"], true);
assert_eq!(actual["gas_used"], 4065i64);
assert_eq!(actual["response"], response);
cleanup_temp_contract_file(&temp);
}
}
59 changes: 44 additions & 15 deletions tvm_debugger/src/result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ pub struct ExecutionResult {
is_json: bool,
log: Vec<String>,
messages: Vec<Value>,
response: String,
response: Value,
response_code: i32,
pub(crate) is_vm_success: bool,
gas_used: i64,
}

impl ExecutionResult {
Expand All @@ -16,24 +19,48 @@ impl ExecutionResult {
is_json,
log: vec![],
messages: vec![],
response: "{}".to_string(),
response: "{}".into(),
response_code: -1,
is_vm_success: false,
gas_used: 0,
};
}

pub fn exit_code(&mut self, code: i32) {
self.response_code = code;
self.log(format!("TVM terminated with exit code {}", code));
}

pub fn vm_success(&mut self, is_vm_success: bool) {
self.is_vm_success = is_vm_success;
self.log(format!("Computing phase is success: {}", is_vm_success));
}

pub fn gas_used(&mut self, gas: i64) {
self.gas_used = gas;
self.log(format!("Gas used: {}", self.gas_used));
self.log("".to_string());
}

pub fn response(&mut self, data: String) {
self.response = data.clone();
self.push(data);
self.response = serde_json::from_str(&*data.clone()).expect("Failed to parse JSON");
self.log(data);
}

pub fn add_out_message(&mut self, message: Message) {
match message.header() {
CommonMsgInfo::IntMsgInfo(_) => {
let state_init = match message.state_init() {
None => None,
Some(state_init) => Some(base64_encode(state_init.write_to_bytes().unwrap())),
};
let destination =
message.header().get_dst_address().unwrap_or_default().to_string();
let body =
tree_of_cells_into_base64(message.body().map(|s| s.into_cell()).as_ref());
let boc = base64_encode(message.write_to_bytes().unwrap());
self.messages.push(json!({
"state_init": state_init,
"destination": destination,
"body": body,
"boc": boc,
Expand All @@ -44,19 +71,21 @@ impl ExecutionResult {
}
}

pub fn push(&mut self, data: String) {
pub fn log(&mut self, data: String) {
self.log.push(data);
}

pub fn print(&mut self) {
if self.is_json {
let messages =
serde_json::to_string(&self.messages).unwrap_or_else(|_| "[]".to_string());
println!(r#"{{"response":{},"messages":{}}}"#, self.response, messages);
} else {
for item in self.log.clone() {
println!("{}", item);
}
}
pub fn to_json(&self) -> Value {
json!({
"exit_code": self.response_code,
"vm_success": self.is_vm_success,
"gas_used": self.gas_used,
"response": self.response,
"messages": self.messages,
})
}

pub fn output(&mut self) -> String {
return if self.is_json { self.to_json().to_string() } else { self.log.join("\n") };
}
}

0 comments on commit 703d64f

Please sign in to comment.