diff --git a/packages/fuels-programs/src/call_utils.rs b/packages/fuels-programs/src/call_utils.rs index d8586b55b..28aa12259 100644 --- a/packages/fuels-programs/src/call_utils.rs +++ b/packages/fuels-programs/src/call_utils.rs @@ -946,4 +946,112 @@ mod test { expected_asset_id_amounts ) } + + mod compute_calls_instructions_len { + use fuel_asm::Instruction; + use fuels_core::types::{enum_variants::EnumVariants, param_types::ParamType}; + + use crate::{call_utils::compute_calls_instructions_len, contract::ContractCall}; + + // movi, movi, lw, movi + call (for gas) + const BASE_INSTRUCTION_COUNT: usize = 5; + // 2 instructions (movi and lw) added in get_single_call_instructions when gas_offset is set + const GAS_OFFSET_INSTRUCTION_COUNT: usize = 2; + // 4 instructions (lw, lw, muli, retd) added by extract_data_receipt + const EXTRACT_DATA_RECEIPT_INSTRUCTION_COUNT: usize = 4; + // 4 instructions (movi, lw, jnef, retd) added by extract_heap_data + const EXTRACT_HEAP_DATA_INSTRUCTION_COUNT: usize = 4; + + #[test] + fn test_simple() { + let call = ContractCall::new_with_random_id(); + let instructions_len = compute_calls_instructions_len(&[call]).unwrap(); + assert_eq!(instructions_len, Instruction::SIZE * BASE_INSTRUCTION_COUNT); + } + + #[test] + fn test_with_gas_offset() { + let mut call = ContractCall::new_with_random_id(); + call.call_parameters = call.call_parameters.with_gas_forwarded(0); + let instructions_len = compute_calls_instructions_len(&[call]).unwrap(); + assert_eq!( + instructions_len, + Instruction::SIZE * (BASE_INSTRUCTION_COUNT + GAS_OFFSET_INSTRUCTION_COUNT) + ); + } + + #[test] + fn test_with_heap_type() { + let output_params = vec![ + ParamType::Vector(Box::new(ParamType::U8)), + ParamType::String, + ParamType::Bytes, + ]; + for output_param in output_params { + let mut call = ContractCall::new_with_random_id(); + call.output_param = output_param; + let instructions_len = compute_calls_instructions_len(&[call]).unwrap(); + assert_eq!( + instructions_len, + Instruction::SIZE + * (BASE_INSTRUCTION_COUNT + EXTRACT_DATA_RECEIPT_INSTRUCTION_COUNT) + ); + } + } + + #[test] + fn test_with_gas_offset_and_heap_type() { + let mut call = ContractCall::new_with_random_id(); + call.call_parameters = call.call_parameters.with_gas_forwarded(0); + call.output_param = ParamType::Vector(Box::new(ParamType::U8)); + let instructions_len = compute_calls_instructions_len(&[call]).unwrap(); + assert_eq!( + instructions_len, + // combines extra instructions from two above tests + Instruction::SIZE + * (BASE_INSTRUCTION_COUNT + + GAS_OFFSET_INSTRUCTION_COUNT + + EXTRACT_DATA_RECEIPT_INSTRUCTION_COUNT) + ); + } + + #[test] + fn test_with_enum_with_heap_and_non_heap_variant() { + let variant_sets = vec![ + vec![ParamType::Vector(Box::new(ParamType::U8)), ParamType::U8], + vec![ParamType::String, ParamType::U8], + vec![ParamType::Bytes, ParamType::U8], + ]; + for variant_set in variant_sets { + let mut call = ContractCall::new_with_random_id(); + call.output_param = ParamType::Enum { + variants: EnumVariants::new(variant_set).unwrap(), + generics: Vec::new(), + }; + let instructions_len = compute_calls_instructions_len(&[call]).unwrap(); + assert_eq!( + instructions_len, + Instruction::SIZE + * (BASE_INSTRUCTION_COUNT + + EXTRACT_DATA_RECEIPT_INSTRUCTION_COUNT + + EXTRACT_HEAP_DATA_INSTRUCTION_COUNT) + ); + } + } + + #[test] + fn test_with_enum_with_only_non_heap_variants() { + let mut call = ContractCall::new_with_random_id(); + call.output_param = ParamType::Enum { + variants: EnumVariants::new(vec![ParamType::Bool, ParamType::U8]).unwrap(), + generics: Vec::new(), + }; + let instructions_len = compute_calls_instructions_len(&[call]).unwrap(); + assert_eq!( + instructions_len, + // no extra instructions if there are no heap type variants + Instruction::SIZE * BASE_INSTRUCTION_COUNT + ); + } + } }