diff --git a/src/clarity.rs b/src/clarity.rs index 2f417699b..a000926f0 100644 --- a/src/clarity.rs +++ b/src/clarity.rs @@ -581,7 +581,7 @@ impl HeadersDB for CLIHeadersDB { fn get_eval_input(invoked_by: &str, args: &[String]) -> EvalInput { if args.len() < 3 || args.len() > 4 { eprintln!( - "Usage: {} {} [contract-identifier] (program.clar) [vm-state.db]", + "Usage: {} {} [--costs] [contract-identifier] (program.clar) [vm-state.db]", invoked_by, args[0] ); panic_test!(); @@ -1051,12 +1051,6 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option { - let mut argv: Vec = args.into_iter().map(|x| x.clone()).collect(); - let mainnet = if let Ok(Some(_)) = consume_arg(&mut argv, &["--testnet"], false) { - false - } else { - true - }; let content: String = { let mut buffer = String::new(); friendly_expect( @@ -1068,7 +1062,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option { - let evalInput = get_eval_input(invoked_by, args); - let vm_filename = if args.len() == 3 { &args[2] } else { &args[3] }; + let mut argv: Vec = args.into_iter().map(|x| x.clone()).collect(); + + let costs = if let Ok(Some(_)) = consume_arg(&mut argv, &["--costs"], false) { + true + } else { + false + }; + + let evalInput = get_eval_input(invoked_by, &argv); + let vm_filename = if argv.len() == 3 { &argv[2] } else { &argv[3] }; let header_db = friendly_expect(CLIHeadersDB::resume(vm_filename), "Failed to open CLI DB"); let marf_kv = friendly_expect( @@ -1114,41 +1116,68 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option ( - 0, - Some(json!({ - "output": serde_json::to_value(&x).unwrap() - })), - ), - Err(error) => ( - 1, - Some(json!({ + match result_and_cost { + (Ok(result), cost) => { + let mut result_json = json!({ + "output": serde_json::to_value(&result).unwrap() + }); + + if costs { + result_json["costs"] = serde_json::to_value(&cost).unwrap(); + } + + (0, Some(result_json)) + } + (Err(error), cost) => { + let mut result_json = json!({ "error": { "runtime": serde_json::to_value(&format!("{}", error)).unwrap() } - })), - ), + }); + + if costs { + result_json["costs"] = serde_json::to_value(&cost).unwrap(); + } + + (1, Some(result_json)) + } } } "eval_at_chaintip" => { - let evalInput = get_eval_input(invoked_by, args); - let vm_filename = if args.len() == 3 { &args[2] } else { &args[3] }; + let mut argv: Vec = args.into_iter().map(|x| x.clone()).collect(); + + let costs = if let Ok(Some(_)) = consume_arg(&mut argv, &["--costs"], false) { + true + } else { + false + }; + + let evalInput = get_eval_input(invoked_by, &argv); + let vm_filename = if argv.len() == 3 { &argv[2] } else { &argv[3] }; let header_db = friendly_expect(CLIHeadersDB::resume(vm_filename), "Failed to open CLI DB"); let marf_kv = friendly_expect( @@ -1156,49 +1185,75 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option ( - 0, - Some(json!({ - "output": serde_json::to_value(&x).unwrap() - })), - ), - Err(error) => ( - 1, - Some(json!({ + match result_and_cost { + (Ok(result), cost) => { + let mut result_json = json!({ + "output": serde_json::to_value(&result).unwrap() + }); + + if costs { + result_json["costs"] = serde_json::to_value(&cost).unwrap(); + } + + (0, Some(result_json)) + } + (Err(error), cost) => { + let mut result_json = json!({ "error": { "runtime": serde_json::to_value(&format!("{}", error)).unwrap() } - })), - ), + }); + + if costs { + result_json["costs"] = serde_json::to_value(&cost).unwrap(); + } + + (1, Some(result_json)) + } } } "eval_at_block" => { - if args.len() != 4 { + let mut argv: Vec = args.into_iter().map(|x| x.clone()).collect(); + + let costs = if let Ok(Some(_)) = consume_arg(&mut argv, &["--costs"], false) { + true + } else { + false + }; + + if argv.len() != 4 { eprintln!( - "Usage: {} {} [index-block-hash] [contract-identifier] [vm/clarity dir]", - invoked_by, &args[0] + "Usage: {} {} [--costs] [index-block-hash] [contract-identifier] [vm/clarity dir]", + invoked_by, &argv[0] ); panic_test!(); } - let chain_tip = &args[1]; + let chain_tip = &argv[1]; let contract_identifier = friendly_expect( - QualifiedContractIdentifier::parse(&args[2]), + QualifiedContractIdentifier::parse(&argv[2]), "Failed to parse contract identifier.", ); let content: String = { @@ -1210,7 +1265,7 @@ pub fn invoke_command(invoked_by: &str, args: &[String]) -> (i32, Option (i32, Option ( - 0, - Some(json!({ - "output": serde_json::to_value(&x).unwrap() - })), - ), - Err(error) => ( - 1, - Some(json!({ + match result_and_cost { + (Ok(result), cost) => { + let mut result_json = json!({ + "output": serde_json::to_value(&result).unwrap() + }); + + if costs { + result_json["costs"] = serde_json::to_value(&cost).unwrap(); + } + + (0, Some(result_json)) + } + (Err(error), cost) => { + let mut result_json = json!({ "error": { "runtime": serde_json::to_value(&format!("{}", error)).unwrap() } - })), - ), + }); + + if costs { + result_json["costs"] = serde_json::to_value(&cost).unwrap(); + } + + (1, Some(result_json)) + } } } "launch" => { @@ -1801,6 +1874,35 @@ mod test { }) ); + eprintln!("eval tokens with cost"); + let invoked = invoke_command( + "test", + &[ + "eval".to_string(), + "--costs".to_string(), + "S1G2081040G2081040G2081040G208105NK8PE5.tokens".to_string(), + "sample-contracts/tokens-mint.clar".to_string(), + db_name.clone(), + ], + ); + + let exit = invoked.0; + let result = invoked.1.unwrap(); + + assert_eq!(exit, 0); + assert_eq!( + result["output"], + json!({ + "Response": { + "committed": true, + "data": { + "UInt": 100 + } + } + }) + ); + assert!(result["costs"] != json!(null)); + eprintln!("eval_at_chaintip tokens"); let invoked = invoke_command( "test", @@ -1827,6 +1929,35 @@ mod test { } }) ); + + eprintln!("eval_at_chaintip tokens with cost"); + let invoked = invoke_command( + "test", + &[ + "eval_at_chaintip".to_string(), + "S1G2081040G2081040G2081040G208105NK8PE5.tokens".to_string(), + "sample-contracts/tokens-mint.clar".to_string(), + db_name.clone(), + "--costs".to_string(), + ], + ); + + let exit = invoked.0; + let result = invoked.1.unwrap(); + + assert_eq!(exit, 0); + assert_eq!( + result["output"], + json!({ + "Response": { + "committed": true, + "data": { + "UInt": 100 + } + } + }) + ); + assert!(result["costs"] != json!(null)); } #[test]