diff --git a/sway-lib-std/src/inputs.sw b/sway-lib-std/src/inputs.sw index 00174fb194e..fd5c28530fc 100644 --- a/sway-lib-std/src/inputs.sw +++ b/sway-lib-std/src/inputs.sw @@ -586,11 +586,16 @@ pub fn input_message_data(index: u64, offset: u64) -> Option { Some(Input::Message) => { let data = __gtf::(index, GTF_INPUT_MESSAGE_DATA); let data_with_offset = data.add_uint_offset(offset); - let length = input_message_data_length(index).unwrap(); - let new_ptr = alloc_bytes(length); + let total_length = input_message_data_length(index).unwrap(); + if offset > total_length { + return None + } + let offset_length = total_length - offset; - data_with_offset.copy_bytes_to(new_ptr, length); - Some(Bytes::from(raw_slice::from_parts::(new_ptr, length))) + let new_ptr = alloc_bytes(offset_length); + + data_with_offset.copy_bytes_to(new_ptr, offset_length); + Some(Bytes::from(raw_slice::from_parts::(new_ptr, offset_length))) }, _ => None, } diff --git a/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw b/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw index 8429acd0c62..ed80700620c 100644 --- a/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/tx_contract/src/main.sw @@ -40,7 +40,7 @@ abi TxContractTest { fn get_input_message_data_length(index: u64) -> Option; fn get_input_predicate_length(index: u64) -> Option; fn get_input_predicate_data_length(index: u64) -> Option; - fn get_input_message_data(index: u64, offset: u64, expected: [u8; 3]) -> bool; + fn get_input_message_data(index: u64, offset: u64, expected_data_bytes: Bytes) -> bool; fn get_input_predicate(index: u64, bytecode: Vec) -> bool; fn get_output_type(ptr: u64) -> Option; @@ -123,18 +123,25 @@ impl TxContractTest for Contract { fn get_input_predicate_data_length(index: u64) -> Option { input_predicate_data_length(index) } - fn get_input_message_data(index: u64, offset: u64, expected: [u8; 3]) -> bool { + fn get_input_message_data(index: u64, offset: u64, expected_data_bytes: Bytes) -> bool { let data = match input_message_data(index, offset) { Some(b) => b, None => return false, }; - let mut expected_data_bytes = Bytes::new(); + if expected_data_bytes.len() != data.len() { + return false + } + + let mut iter = 0; + while iter < expected_data_bytes.len() { + if data.get(iter).unwrap() != expected_data_bytes.get(iter).unwrap() { + return false + } + iter += 1; + } - expected_data_bytes.push(expected[0]); - expected_data_bytes.push(expected[1]); - expected_data_bytes.push(expected[2]); - (data.get(0).unwrap() == expected_data_bytes.get(0).unwrap()) && (data.get(1).unwrap() == expected_data_bytes.get(1).unwrap()) && (data.get(2).unwrap() == expected_data_bytes.get(2).unwrap()) + return true } fn get_input_predicate(index: u64, bytecode: Vec) -> bool { diff --git a/test/src/sdk-harness/test_projects/tx_fields/mod.rs b/test/src/sdk-harness/test_projects/tx_fields/mod.rs index c29f93c7176..aace3c9fa38 100644 --- a/test/src/sdk-harness/test_projects/tx_fields/mod.rs +++ b/test/src/sdk-harness/test_projects/tx_fields/mod.rs @@ -890,7 +890,7 @@ mod inputs { let mut builder = contract_instance .methods() - .get_input_message_data(3, 0, MESSAGE_DATA) + .get_input_message_data(3, 0, Bytes(MESSAGE_DATA.into())) .transaction_builder() .await .unwrap(); @@ -920,7 +920,7 @@ mod inputs { // Assert none returned when transaction type is not a message let none_result = contract_instance .methods() - .get_input_message_data(3, 0, MESSAGE_DATA) + .get_input_message_data(3, 0, Bytes(MESSAGE_DATA.into())) .call() .await .unwrap(); @@ -928,6 +928,78 @@ mod inputs { assert_eq!(none_result.value, false); } + #[tokio::test] + async fn can_get_input_message_data_with_offset() { + let (contract_instance, _, wallet, _) = get_contracts(true).await; + let message = &wallet.get_messages().await.unwrap()[0]; + let provider = wallet.provider().unwrap(); + + let mut builder = contract_instance + .methods() + .get_input_message_data(3, 1, Bytes(MESSAGE_DATA[1..].into())) + .transaction_builder() + .await + .unwrap(); + + wallet.adjust_for_fee(&mut builder, 1000).await.unwrap(); + + builder.inputs_mut().push(SdkInput::ResourceSigned { + resource: CoinType::Message(message.clone()), + }); + + builder.add_signer(wallet.clone()).unwrap(); + + let tx = builder.build(provider).await.unwrap(); + + let provider = wallet.provider().unwrap(); + let tx_id = provider.send_transaction(tx).await.unwrap(); + + let receipts = provider + .tx_status(&tx_id) + .await + .unwrap() + .take_receipts_checked(None) + .unwrap(); + + assert_eq!(receipts[1].data(), Some(&[1][..])); + } + + #[tokio::test] + async fn input_message_data_none_when_offset_exceeds_length() { + let (contract_instance, _, wallet, _) = get_contracts(true).await; + let message = &wallet.get_messages().await.unwrap()[0]; + let provider = wallet.provider().unwrap(); + + let mut builder = contract_instance + .methods() + .get_input_message_data(3, (MESSAGE_DATA.len() + 1) as u64, Bytes(MESSAGE_DATA.into())) + .transaction_builder() + .await + .unwrap(); + + wallet.adjust_for_fee(&mut builder, 1000).await.unwrap(); + + builder.inputs_mut().push(SdkInput::ResourceSigned { + resource: CoinType::Message(message.clone()), + }); + + builder.add_signer(wallet.clone()).unwrap(); + + let tx = builder.build(provider).await.unwrap(); + + let provider = wallet.provider().unwrap(); + let tx_id = provider.send_transaction(tx).await.unwrap(); + + let receipts = provider + .tx_status(&tx_id) + .await + .unwrap() + .take_receipts_checked(None) + .unwrap(); + + assert_eq!(receipts[1].data(), Some(&[0][..])); + } + #[tokio::test] async fn can_get_input_message_predicate() { let (contract_instance, _, wallet, _) = get_contracts(true).await;