From 20ee2da4359f73b5584d978800c0ae09e827f436 Mon Sep 17 00:00:00 2001 From: bitzoic Date: Thu, 8 Aug 2024 16:09:24 +0700 Subject: [PATCH 01/10] Increase saftey when introspecting inputs in std-lib --- sway-lib-std/src/auth.sw | 40 +++++----- sway-lib-std/src/inputs.sw | 151 ++++++++++++++++++++----------------- 2 files changed, 99 insertions(+), 92 deletions(-) diff --git a/sway-lib-std/src/auth.sw b/sway-lib-std/src/auth.sw index 4551a8ca7d7..c3b89a9fe3f 100644 --- a/sway-lib-std/src/auth.sw +++ b/sway-lib-std/src/auth.sw @@ -140,34 +140,34 @@ pub fn msg_sender() -> Result { /// } /// ``` pub fn caller_address() -> Result { - let inputs = input_count(); + let inputs = input_count().as_u64(); let mut candidate = None; - let mut i = 0u16; + let mut itter = 0; // Note: `inputs_count` is guaranteed to be at least 1 for any valid tx. - while i < inputs { - let type_of_input = input_type(i.as_u64()); + while itter < inputs { + let type_of_input = input_type(itter); match type_of_input { - Input::Coin => (), - Input::Message => (), + Some(Input::Coin) => (), + Some(Input::Message) => (), _ => { // type != InputCoin or InputMessage, continue looping. - i += 1u16; + itter += 1; continue; } } // type == InputCoin or InputMessage. let owner_of_input = match type_of_input { - Input::Coin => { - input_coin_owner(i.as_u64()) + Some(Input::Coin) => { + input_coin_owner(itter) }, - Input::Message => { - Some(input_message_sender(i.as_u64())) + Some(Input::Message) => { + input_message_sender(itter) }, _ => { // type != InputCoin or InputMessage, continue looping. - i += 1u16; + itter += 1; continue; } }; @@ -175,7 +175,7 @@ pub fn caller_address() -> Result { if candidate.is_none() { // This is the first input seen of the correct type. candidate = owner_of_input; - i += 1u16; + itter += 1; continue; } @@ -184,7 +184,7 @@ pub fn caller_address() -> Result { // at this point, so we can unwrap safely. if owner_of_input.unwrap() == candidate.unwrap() { // Owners are a match, continue looping. - i += 1u16; + itter += 1; continue; } @@ -203,7 +203,7 @@ pub fn caller_address() -> Result { /// /// # Returns /// -/// * [Address] - The address of this predicate. +/// * [Option
] - The address of this predicate. /// /// # Reverts /// @@ -219,7 +219,7 @@ pub fn caller_address() -> Result { /// log(this_predicate); /// } /// ``` -pub fn predicate_address() -> Address { +pub fn predicate_address() -> Option
{ // Get index of current predicate. // i3 = GM_GET_VERIFYING_PREDICATE let predicate_index = asm(r1) { @@ -230,10 +230,8 @@ pub fn predicate_address() -> Address { let type_of_input = input_type(predicate_index); match type_of_input { - Input::Coin => input_coin_owner(predicate_index).unwrap(), - Input::Message => input_message_recipient(predicate_index), - _ => { - revert(0) - } + Some(Input::Coin) => input_coin_owner(predicate_index), + Some(Input::Message) => input_message_recipient(predicate_index), + _ => { None } } } diff --git a/sway-lib-std/src/inputs.sw b/sway-lib-std/src/inputs.sw index 622041e8d5f..599b0d19230 100644 --- a/sway-lib-std/src/inputs.sw +++ b/sway-lib-std/src/inputs.sw @@ -83,7 +83,7 @@ impl Eq for Input { /// /// # Returns /// -/// * [Input] - The type of the input at `index`. +/// * [Option] - The type of the input at `index`. /// /// # Examples /// @@ -91,16 +91,16 @@ impl Eq for Input { /// use std::inputs::input_type; /// /// fn foo() { -/// let input_type = input_type(0); +/// let input_type = input_type(0).unwrap(); /// assert(input_type == Input::Coin); /// } /// ``` -pub fn input_type(index: u64) -> Input { +pub fn input_type(index: u64) -> Option { match __gtf::(index, GTF_INPUT_TYPE) { - 0u8 => Input::Coin, - 1u8 => Input::Contract, - 2u8 => Input::Message, - _ => revert(0), + 0u8 => Some(Input::Coin), + 1u8 => Some(Input::Contract), + 2u8 => Some(Input::Message), + _ => None, } } @@ -175,9 +175,9 @@ pub fn input_pointer(index: u64) -> u64 { /// ``` pub fn input_amount(index: u64) -> Option { match input_type(index) { - Input::Coin => Some(__gtf::(index, GTF_INPUT_COIN_AMOUNT)), - Input::Message => Some(__gtf::(index, GTF_INPUT_MESSAGE_AMOUNT)), - Input::Contract => None, + Some(Input::Coin) => Some(__gtf::(index, GTF_INPUT_COIN_AMOUNT)), + Some(Input::Message) => Some(__gtf::(index, GTF_INPUT_MESSAGE_AMOUNT)), + _ => None, } } @@ -203,7 +203,7 @@ pub fn input_amount(index: u64) -> Option { /// ``` pub fn input_coin_owner(index: u64) -> Option
{ match input_type(index) { - Input::Coin => Some(Address::from(__gtf::(index, GTF_INPUT_COIN_OWNER))), + Some(Input::Coin) => Some(Address::from(__gtf::(index, GTF_INPUT_COIN_OWNER))), _ => None, } } @@ -229,9 +229,9 @@ pub fn input_coin_owner(index: u64) -> Option
{ /// } pub fn input_predicate_data_pointer(index: u64) -> Option { match input_type(index) { - Input::Coin => Some(__gtf::(index, GTF_INPUT_COIN_PREDICATE_DATA)), - Input::Message => Some(__gtf::(index, GTF_INPUT_MESSAGE_PREDICATE_DATA)), - Input::Contract => None, + Some(Input::Coin) => Some(__gtf::(index, GTF_INPUT_COIN_PREDICATE_DATA)), + Some(Input::Message) => Some(__gtf::(index, GTF_INPUT_MESSAGE_PREDICATE_DATA)), + _ => None, } } @@ -243,7 +243,7 @@ pub fn input_predicate_data_pointer(index: u64) -> Option { /// /// # Returns /// -/// * [T] - The predicate data of the input at `index`. +/// * [Option] - The predicate data of the input at `index`. /// /// # Examples /// @@ -255,12 +255,15 @@ pub fn input_predicate_data_pointer(index: u64) -> Option { /// assert(input_predicate_data == 100); /// } /// ``` -pub fn input_predicate_data(index: u64) -> T +pub fn input_predicate_data(index: u64) -> Option where T: AbiDecode, { - use core::codec::decode_predicate_data_by_index; - decode_predicate_data_by_index::(index) + match input_type(index) { + Some(Input::Coin) => Some(core::codec::decode_predicate_data_by_index::(index)), + Some(Input::Message) => Some(core::codec::decode_predicate_data_by_index::(index)), + _ => None, + } } /// Gets the AssetId of the input at `index`. @@ -285,9 +288,9 @@ where /// ``` pub fn input_asset_id(index: u64) -> Option { match input_type(index) { - Input::Coin => Some(AssetId::from(__gtf::(index, GTF_INPUT_COIN_ASSET_ID))), - Input::Message => Some(AssetId::base()), - Input::Contract => None, + Some(Input::Coin) => Some(AssetId::from(__gtf::(index, GTF_INPUT_COIN_ASSET_ID))), + Some(Input::Message) => Some(AssetId::base()), + _ => None, } } @@ -313,9 +316,9 @@ pub fn input_asset_id(index: u64) -> Option { /// ``` pub fn input_witness_index(index: u64) -> Option { match input_type(index) { - Input::Coin => Some(__gtf::(index, GTF_INPUT_COIN_WITNESS_INDEX)), - Input::Message => Some(__gtf::(index, GTF_INPUT_MESSAGE_WITNESS_INDEX)), - Input::Contract => None, + Some(Input::Coin) => Some(__gtf::(index, GTF_INPUT_COIN_WITNESS_INDEX)), + Some(Input::Message) => Some(__gtf::(index, GTF_INPUT_MESSAGE_WITNESS_INDEX)), + _ => None, } } @@ -341,9 +344,9 @@ pub fn input_witness_index(index: u64) -> Option { /// ``` pub fn input_predicate_length(index: u64) -> Option { match input_type(index) { - Input::Coin => Some(__gtf::(index, GTF_INPUT_COIN_PREDICATE_LENGTH)), - Input::Message => Some(__gtf::(index, GTF_INPUT_MESSAGE_PREDICATE_LENGTH)), - Input::Contract => None, + Some(Input::Coin) => Some(__gtf::(index, GTF_INPUT_COIN_PREDICATE_LENGTH)), + Some(Input::Message) => Some(__gtf::(index, GTF_INPUT_MESSAGE_PREDICATE_LENGTH)), + _ => None, } } @@ -369,9 +372,9 @@ pub fn input_predicate_length(index: u64) -> Option { /// ``` pub fn input_predicate_pointer(index: u64) -> Option { match input_type(index) { - Input::Coin => Some(__gtf::(index, GTF_INPUT_COIN_PREDICATE)), - Input::Message => Some(__gtf::(index, GTF_INPUT_MESSAGE_PREDICATE)), - Input::Contract => None, + Some(Input::Coin) => Some(__gtf::(index, GTF_INPUT_COIN_PREDICATE)), + Some(Input::Message) => Some(__gtf::(index, GTF_INPUT_MESSAGE_PREDICATE)), + _ => None, } } @@ -383,11 +386,7 @@ pub fn input_predicate_pointer(index: u64) -> Option { /// /// # Returns /// -/// * [Bytes] - The predicate bytecode of the input at `index`, if the input's type is `Input::Coin` or `Input::Message`. -/// -/// # Reverts -/// -/// * When the input's type is not `Input::Coin` or `Input::Message`. +/// * [Option] - The predicate bytecode of the input at `index`, if the input's type is `Input::Coin` or `Input::Message`. /// /// # Examples /// @@ -395,23 +394,24 @@ pub fn input_predicate_pointer(index: u64) -> Option { /// use std::inputs::input_predicate; /// /// fn foo() { -/// let input_predicate = input_predicate(0); +/// let input_predicate = input_predicate(0).unwrap(); /// assert(input_predicate.len() != 0); /// } /// ``` -pub fn input_predicate(index: u64) -> Bytes { +pub fn input_predicate(index: u64) -> Option { let wrapped = input_predicate_length(index); if wrapped.is_none() { - revert(0); - }; + return None + } + let length = wrapped.unwrap(); - let new_ptr = alloc_bytes(length); match input_predicate_pointer(index) { Some(d) => { + let new_ptr = alloc_bytes(length); d.copy_bytes_to(new_ptr, length); - Bytes::from(raw_slice::from_parts::(new_ptr, length)) + Some(Bytes::from(raw_slice::from_parts::(new_ptr, length))) }, - None => revert(0), + None => None, } } @@ -437,9 +437,9 @@ pub fn input_predicate(index: u64) -> Bytes { /// ``` pub fn input_predicate_data_length(index: u64) -> Option { match input_type(index) { - Input::Coin => Some(__gtf::(index, GTF_INPUT_COIN_PREDICATE_DATA_LENGTH)), - Input::Message => Some(__gtf::(index, GTF_INPUT_MESSAGE_PREDICATE_DATA_LENGTH)), - Input::Contract => None, + Some(Input::Coin) => Some(__gtf::(index, GTF_INPUT_COIN_PREDICATE_DATA_LENGTH)), + Some(Input::Message) => Some(__gtf::(index, GTF_INPUT_MESSAGE_PREDICATE_DATA_LENGTH)), + _ => None, } } @@ -453,7 +453,7 @@ pub fn input_predicate_data_length(index: u64) -> Option { /// /// # Returns /// -/// * [Address] - The sender of the input message at `index`, if the input's type is `Input::Message`. +/// * [Option
] - The sender of the input message at `index`, if the input's type is `Input::Message`. /// /// # Examples /// @@ -461,12 +461,15 @@ pub fn input_predicate_data_length(index: u64) -> Option { /// use std::inputs::input_message_sender; /// /// fn foo() { -/// let input_message_sender = input_message_sender(0); +/// let input_message_sender = input_message_sender(0).unwrap(); /// assert(input_message_sender != Address::zero()); /// } /// ``` -pub fn input_message_sender(index: u64) -> Address { - Address::from(__gtf::(index, GTF_INPUT_MESSAGE_SENDER)) +pub fn input_message_sender(index: u64) -> Option
{ + match input_type(index) { + Some(Input::Message) => Some(Address::from(__gtf::(index, GTF_INPUT_MESSAGE_SENDER))), + _ => None, + } } /// Gets the recipient of the input message at `index`. @@ -477,7 +480,7 @@ pub fn input_message_sender(index: u64) -> Address { /// /// # Returns /// -/// * [Address] - The recipient of the input message at `index`, if the input's type is `Input::Message`. +/// * [Option
] - The recipient of the input message at `index`, if the input's type is `Input::Message`. /// /// # Examples /// @@ -485,12 +488,15 @@ pub fn input_message_sender(index: u64) -> Address { /// use std::inputs::input_message_recipient; /// /// fn foo() { -/// let input_message_recipient = input_message_recipient(0); +/// let input_message_recipient = input_message_recipient(0).unwrap(); /// assert(input_message_recipient != Address::zero()); /// } /// ``` -pub fn input_message_recipient(index: u64) -> Address { - Address::from(__gtf::(index, GTF_INPUT_MESSAGE_RECIPIENT)) +pub fn input_message_recipient(index: u64) -> Option
{ + match input_type(index) { + Some(Input::Message) => Some(Address::from(__gtf::(index, GTF_INPUT_MESSAGE_RECIPIENT))), + _ => None, + } } /// Gets the nonce of input message at `index`. @@ -525,7 +531,7 @@ pub fn input_message_nonce(index: u64) -> b256 { /// /// # Returns /// -/// * [u64] - The length of the input message at `index`, if the input's type is `Input::Message`. +/// * [Option] - The length of the input message at `index`, if the input's type is `Input::Message`. /// /// # Examples /// @@ -533,12 +539,15 @@ pub fn input_message_nonce(index: u64) -> b256 { /// use std::inputs::input_message_length; /// /// fn foo() { -/// let input_message_length = input_message_length(0); +/// let input_message_length = input_message_length(0).unwrap(); /// assert(input_message_length != 0_u64); /// } /// ``` -pub fn input_message_data_length(index: u64) -> u64 { - __gtf::(index, GTF_INPUT_MESSAGE_DATA_LENGTH) +pub fn input_message_data_length(index: u64) -> Option { + match input_type(index) { + Some(Input::Message) => Some(__gtf::(index, GTF_INPUT_MESSAGE_DATA_LENGTH)), + _ => None, + } } /// Gets the data of the input message at `index`. @@ -550,7 +559,7 @@ pub fn input_message_data_length(index: u64) -> u64 { /// /// # Returns /// -/// * [Bytes] - The data of the input message at `index`, if the input's type is `Input::Message`. +/// * [Option(Bytes)] - The data of the input message at `index`, if the input's type is `Input::Message`. /// /// # Reverts /// @@ -562,21 +571,21 @@ pub fn input_message_data_length(index: u64) -> u64 { /// use std::inputs::input_message_data; /// /// fn foo() { -/// let input_message_data = input_message_data(0, 0); +/// let input_message_data = input_message_data(0, 0).unwrap(); /// assert(input_message_data.len() != 0); /// } /// ``` -pub fn input_message_data(index: u64, offset: u64) -> Bytes { - assert(valid_input_type(index, 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); - let new_ptr = alloc_bytes(length); - - data_with_offset.copy_bytes_to(new_ptr, length); - Bytes::from(raw_slice::from_parts::(new_ptr, length)) -} +pub fn input_message_data(index: u64, offset: u64) -> Option { + match input_type(index) { + 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_or(return None); + let new_ptr = alloc_bytes(length); -fn valid_input_type(index: u64, expected_type: Input) -> bool { - input_type(index) == expected_type + data_with_offset.copy_bytes_to(new_ptr, length); + Some(Bytes::from(raw_slice::from_parts::(new_ptr, length))) + }, + _ => None, + } } From 727ec24099447e6d58188586c65384a2eb8562f8 Mon Sep 17 00:00:00 2001 From: bitzoic Date: Thu, 8 Aug 2024 16:09:35 +0700 Subject: [PATCH 02/10] Update sdk-harness --- .../test_artifacts/auth_predicate/src/main.sw | 6 ++++- .../test_artifacts/tx_contract/src/main.sw | 27 ++++++++++++------- .../predicate_data_simple/src/main.sw | 5 +++- .../predicate_data_struct/src/main.sw | 5 +++- .../test_projects/tx_fields/mod.rs | 4 +-- 5 files changed, 32 insertions(+), 15 deletions(-) diff --git a/test/src/sdk-harness/test_artifacts/auth_predicate/src/main.sw b/test/src/sdk-harness/test_artifacts/auth_predicate/src/main.sw index 6541dc66529..16268669f3e 100644 --- a/test/src/sdk-harness/test_artifacts/auth_predicate/src/main.sw +++ b/test/src/sdk-harness/test_artifacts/auth_predicate/src/main.sw @@ -3,5 +3,9 @@ predicate; use std::auth::predicate_address; fn main(address: Address) -> bool { - address == predicate_address() + let result = match predicate_address() { + Some(address) => address, + None => return false, + }; + address == result } 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 5755298265c..48c939e5a86 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 @@ -34,16 +34,16 @@ abi TxContractTest { fn get_tx_id() -> b256; fn get_tx_script_bytecode_hash() -> b256; - fn get_input_type(index: u64) -> Input; + fn get_input_type(index: u64) -> Option; fn get_tx_input_pointer(index: u64) -> u64; fn get_input_coin_owner(index: u64) -> Address; fn get_input_amount(index: u64) -> u64; fn get_tx_input_predicate_data_pointer(index: u64) -> u64; - fn get_input_message_sender(index: u64) -> Address; - fn get_input_message_recipient(index: u64) -> Address; + fn get_input_message_sender(index: u64) -> Option
; + fn get_input_message_recipient(index: u64) -> Option
; fn get_input_message_nonce(index: u64) -> b256; fn get_input_witness_index(index: u64) -> u16; - fn get_input_message_data_length(index: u64) -> u64; + fn get_input_message_data_length(index: u64) -> Option; fn get_input_predicate_length(index: u64) -> u64; fn get_input_predicate_data_length(index: u64) -> u64; fn get_input_message_data(index: u64, offset: u64, expected: [u8; 3]) -> bool; @@ -116,7 +116,7 @@ impl TxContractTest for Contract { fn get_tx_input_pointer(index: u64) -> u64 { input_pointer(index) } - fn get_input_type(index: u64) -> Input { + fn get_input_type(index: u64) -> Option { input_type(index) } fn get_input_coin_owner(index: u64) -> Address { @@ -130,10 +130,10 @@ impl TxContractTest for Contract { r1: u64 } } - fn get_input_message_sender(index: u64) -> Address { + fn get_input_message_sender(index: u64) -> Option
{ input_message_sender(index) } - fn get_input_message_recipient(index: u64) -> Address { + fn get_input_message_recipient(index: u64) -> Option
{ input_message_recipient(index) } fn get_input_message_nonce(index: u64) -> b256 { @@ -142,7 +142,7 @@ impl TxContractTest for Contract { fn get_input_witness_index(index: u64) -> u16 { input_witness_index(index).unwrap() } - fn get_input_message_data_length(index: u64) -> u64 { + fn get_input_message_data_length(index: u64) -> Option { input_message_data_length(index) } fn get_input_predicate_length(index: u64) -> u64 { @@ -152,7 +152,10 @@ impl TxContractTest for Contract { input_predicate_data_length(index).unwrap() } fn get_input_message_data(index: u64, offset: u64, expected: [u8; 3]) -> bool { - let data = input_message_data(index, offset); + let data = match input_message_data(index, offset) { + Some(bytes) => bytes, + None => return false, + }; let mut expected_data_bytes = Bytes::new(); @@ -163,7 +166,11 @@ impl TxContractTest for Contract { } fn get_input_predicate(index: u64, bytecode: Vec) -> bool { - let code = input_predicate(index); + let code = match input_predicate(index) { + Some(code) => code, + None => return false, + }; + assert(input_predicate_length(index).unwrap() == bytecode.len()); let mut i = 0; while i < bytecode.len() { diff --git a/test/src/sdk-harness/test_projects/predicate_data_simple/src/main.sw b/test/src/sdk-harness/test_projects/predicate_data_simple/src/main.sw index 873051e2cc8..c803a2d790c 100644 --- a/test/src/sdk-harness/test_projects/predicate_data_simple/src/main.sw +++ b/test/src/sdk-harness/test_projects/predicate_data_simple/src/main.sw @@ -3,7 +3,10 @@ predicate; use std::inputs::input_predicate_data; fn main() -> bool { - let received: u32 = input_predicate_data::(0); + let received: u32 = match input_predicate_data::(0) { + Some(data) => data, + None => return false, + }; let expected: u32 = 12345; received == expected diff --git a/test/src/sdk-harness/test_projects/predicate_data_struct/src/main.sw b/test/src/sdk-harness/test_projects/predicate_data_struct/src/main.sw index fa1136e3e62..2a977490521 100644 --- a/test/src/sdk-harness/test_projects/predicate_data_struct/src/main.sw +++ b/test/src/sdk-harness/test_projects/predicate_data_struct/src/main.sw @@ -8,6 +8,9 @@ struct Validation { } fn main() -> bool { - let validation: Validation = input_predicate_data::(0); + let validation: Validation = match input_predicate_data::(0) { + Some(data) => data, + None => return false, + }; validation.total_complete == 100 && validation.has_account } 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 463c3b861d3..ec0d12b164f 100644 --- a/test/src/sdk-harness/test_projects/tx_fields/mod.rs +++ b/test/src/sdk-harness/test_projects/tx_fields/mod.rs @@ -528,7 +528,7 @@ mod inputs { .call() .await .unwrap(); - assert_eq!(result.value, Input::Contract); + assert_eq!(result.value, Some(Input::Contract)); let result = contract_instance .methods() @@ -536,7 +536,7 @@ mod inputs { .call() .await .unwrap(); - assert_eq!(result.value, Input::Coin); + assert_eq!(result.value, Some(Input::Coin)); } #[tokio::test] From 243c9c5ca901927bced3444233b4edb1189fa1ee Mon Sep 17 00:00:00 2001 From: bitzoic Date: Fri, 9 Aug 2024 16:17:23 +0700 Subject: [PATCH 03/10] Resolve sdk-harness test errors --- sway-lib-std/src/inputs.sw | 2 +- .../test_artifacts/tx_contract/src/main.sw | 20 +++++++++---------- .../src/sdk-harness/test_projects/auth/mod.rs | 4 ++-- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/sway-lib-std/src/inputs.sw b/sway-lib-std/src/inputs.sw index 599b0d19230..69e87a77fa3 100644 --- a/sway-lib-std/src/inputs.sw +++ b/sway-lib-std/src/inputs.sw @@ -580,7 +580,7 @@ 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_or(return None); + let length = input_message_data_length(index).unwrap(); let new_ptr = alloc_bytes(length); data_with_offset.copy_bytes_to(new_ptr, length); 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 48c939e5a86..a69b7d91f92 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 @@ -39,11 +39,11 @@ abi TxContractTest { fn get_input_coin_owner(index: u64) -> Address; fn get_input_amount(index: u64) -> u64; fn get_tx_input_predicate_data_pointer(index: u64) -> u64; - fn get_input_message_sender(index: u64) -> Option
; - fn get_input_message_recipient(index: u64) -> Option
; + fn get_input_message_sender(index: u64) -> Address; + fn get_input_message_recipient(index: u64) -> Address; fn get_input_message_nonce(index: u64) -> b256; fn get_input_witness_index(index: u64) -> u16; - fn get_input_message_data_length(index: u64) -> Option; + fn get_input_message_data_length(index: u64) -> u64; fn get_input_predicate_length(index: u64) -> u64; fn get_input_predicate_data_length(index: u64) -> u64; fn get_input_message_data(index: u64, offset: u64, expected: [u8; 3]) -> bool; @@ -130,11 +130,11 @@ impl TxContractTest for Contract { r1: u64 } } - fn get_input_message_sender(index: u64) -> Option
{ - input_message_sender(index) + fn get_input_message_sender(index: u64) -> Address { + input_message_sender(index).unwrap() } - fn get_input_message_recipient(index: u64) -> Option
{ - input_message_recipient(index) + fn get_input_message_recipient(index: u64) -> Address { + input_message_recipient(index).unwrap() } fn get_input_message_nonce(index: u64) -> b256 { input_message_nonce(index) @@ -142,8 +142,8 @@ impl TxContractTest for Contract { fn get_input_witness_index(index: u64) -> u16 { input_witness_index(index).unwrap() } - fn get_input_message_data_length(index: u64) -> Option { - input_message_data_length(index) + fn get_input_message_data_length(index: u64) -> u64 { + input_message_data_length(index).unwrap() } fn get_input_predicate_length(index: u64) -> u64 { input_predicate_length(index).unwrap() @@ -153,7 +153,7 @@ impl TxContractTest for Contract { } fn get_input_message_data(index: u64, offset: u64, expected: [u8; 3]) -> bool { let data = match input_message_data(index, offset) { - Some(bytes) => bytes, + Some(b) => b, None => return false, }; diff --git a/test/src/sdk-harness/test_projects/auth/mod.rs b/test/src/sdk-harness/test_projects/auth/mod.rs index 2878354bf03..fcbfd2766eb 100644 --- a/test/src/sdk-harness/test_projects/auth/mod.rs +++ b/test/src/sdk-harness/test_projects/auth/mod.rs @@ -196,7 +196,7 @@ async fn can_get_predicate_address() { // Setup predicate. let hex_predicate_address: &str = - "0x96495296fbfc9bb1f8bfb254354a25138cc7331fc5df620b3f4ac5d90f24ff7f"; + "0xd7c64424d48025fa6047a7508c30c2ea3a7c126e6efcc93f6195f21a48742a1f"; let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string"); let predicate_bech32_address = Bech32Address::from(predicate_address); @@ -322,7 +322,7 @@ async fn when_incorrect_predicate_address_passed() { async fn can_get_predicate_address_in_message() { // Setup predicate address. let hex_predicate_address: &str = - "0x96495296fbfc9bb1f8bfb254354a25138cc7331fc5df620b3f4ac5d90f24ff7f"; + "0xd7c64424d48025fa6047a7508c30c2ea3a7c126e6efcc93f6195f21a48742a1f"; let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string"); let predicate_bech32_address = Bech32Address::from(predicate_address); From a3f9987d56710222e89b5e1529c648ecc56708ab Mon Sep 17 00:00:00 2001 From: bitzoic Date: Fri, 9 Aug 2024 16:28:47 +0700 Subject: [PATCH 04/10] Run formatter --- sway-lib-std/src/auth.sw | 4 +- .../test_artifacts/tx_contract/src/main.sw | 2 +- .../test_projects/tx_fields/mod.rs | 80 +++++++++++-------- 3 files changed, 49 insertions(+), 37 deletions(-) diff --git a/sway-lib-std/src/auth.sw b/sway-lib-std/src/auth.sw index c3b89a9fe3f..35b6b3fb47a 100644 --- a/sway-lib-std/src/auth.sw +++ b/sway-lib-std/src/auth.sw @@ -232,6 +232,8 @@ pub fn predicate_address() -> Option
{ match type_of_input { Some(Input::Coin) => input_coin_owner(predicate_index), Some(Input::Message) => input_message_recipient(predicate_index), - _ => { None } + _ => { + 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 a69b7d91f92..9c58dca0567 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 @@ -170,7 +170,7 @@ impl TxContractTest for Contract { Some(code) => code, None => return false, }; - + assert(input_predicate_length(index).unwrap() == bytecode.len()); let mut i = 0; while i < bytecode.len() { 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 ec0d12b164f..a481af9064f 100644 --- a/test/src/sdk-harness/test_projects/tx_fields/mod.rs +++ b/test/src/sdk-harness/test_projects/tx_fields/mod.rs @@ -4,18 +4,16 @@ use fuels::types::transaction_builders::TransactionBuilder; use fuels::{ accounts::{predicate::Predicate, wallet::WalletUnlocked, Account}, prelude::*, - types::{input::Input as SdkInput, Bits256, output::Output as SdkOutput}, tx::StorageSlot, + types::{input::Input as SdkInput, output::Output as SdkOutput, Bits256}, }; use std::fs; const MESSAGE_DATA: [u8; 3] = [1u8, 2u8, 3u8]; -const TX_CONTRACT_BYTECODE_PATH: &str = - "test_artifacts/tx_contract/out/release/tx_contract.bin"; +const TX_CONTRACT_BYTECODE_PATH: &str = "test_artifacts/tx_contract/out/release/tx_contract.bin"; const TX_OUTPUT_PREDICATE_BYTECODE_PATH: &str = "test_artifacts/tx_output_predicate/out/release/tx_output_predicate.bin"; -const TX_FIELDS_PREDICATE_BYTECODE_PATH: &str = - "test_projects/tx_fields/out/release/tx_fields.bin"; +const TX_FIELDS_PREDICATE_BYTECODE_PATH: &str = "test_projects/tx_fields/out/release/tx_fields.bin"; const TX_CONTRACT_CREATION_PREDICATE_BYTECODE_PATH: &str = "test_artifacts/tx_output_contract_creation_predicate/out/release/tx_output_contract_creation_predicate.bin"; @@ -78,14 +76,11 @@ async fn get_contracts( wallet.set_provider(provider.clone()); deployment_wallet.set_provider(provider); - let contract_id = Contract::load_from( - TX_CONTRACT_BYTECODE_PATH, - LoadConfiguration::default(), - ) - .unwrap() - .deploy(&wallet, TxPolicies::default()) - .await - .unwrap(); + let contract_id = Contract::load_from(TX_CONTRACT_BYTECODE_PATH, LoadConfiguration::default()) + .unwrap() + .deploy(&wallet, TxPolicies::default()) + .await + .unwrap(); let instance = TxContractTest::new(contract_id.clone(), deployment_wallet.clone()); @@ -175,12 +170,10 @@ async fn setup_output_predicate() -> (WalletUnlocked, WalletUnlocked, Predicate, .encode_data(0, Bits256([0u8; 32]), Bits256(*wallet1.address().hash())) .unwrap(); - let predicate = Predicate::load_from( - TX_OUTPUT_PREDICATE_BYTECODE_PATH, - ) - .unwrap() - .with_data(predicate_data) - .with_provider(wallet1.try_provider().unwrap().clone()); + let predicate = Predicate::load_from(TX_OUTPUT_PREDICATE_BYTECODE_PATH) + .unwrap() + .with_data(predicate_data) + .with_provider(wallet1.try_provider().unwrap().clone()); wallet1 .transfer(predicate.address(), 100, asset_id1, TxPolicies::default()) @@ -939,12 +932,17 @@ mod outputs { let provider = wallet.try_provider().unwrap(); // Get the predicate - let predicate: Predicate = Predicate::load_from(TX_CONTRACT_CREATION_PREDICATE_BYTECODE_PATH).unwrap() + let predicate: Predicate = + Predicate::load_from(TX_CONTRACT_CREATION_PREDICATE_BYTECODE_PATH) + .unwrap() .with_provider(provider.clone()); let predicate_coin_amount = 100; - + // Predicate has no funds - let predicate_balance = predicate.get_asset_balance(&provider.base_asset_id()).await.unwrap(); + let predicate_balance = predicate + .get_asset_balance(&provider.base_asset_id()) + .await + .unwrap(); assert_eq!(predicate_balance, 0); // Transfer funds to predicate @@ -955,10 +953,14 @@ mod outputs { *provider.base_asset_id(), TxPolicies::default(), ) - .await.unwrap(); + .await + .unwrap(); // Predicate has funds - let predicate_balance = predicate.get_asset_balance(&provider.base_asset_id()).await.unwrap(); + let predicate_balance = predicate + .get_asset_balance(&provider.base_asset_id()) + .await + .unwrap(); assert_eq!(predicate_balance, predicate_coin_amount); // Get contract ready for deployment @@ -968,19 +970,21 @@ mod outputs { let contract = Contract::new(binary.clone(), salt, storage_slots.clone()); // Start building the transaction - let tb: CreateTransactionBuilder = CreateTransactionBuilder::prepare_contract_deployment( - binary, - contract.contract_id(), - contract.state_root(), - salt, - storage_slots, - TxPolicies::default(), - ); + let tb: CreateTransactionBuilder = + CreateTransactionBuilder::prepare_contract_deployment( + binary, + contract.contract_id(), + contract.state_root(), + salt, + storage_slots, + TxPolicies::default(), + ); // Inputs let inputs = predicate .get_asset_inputs_for_amount(*provider.base_asset_id(), predicate_coin_amount, None) - .await.unwrap(); + .await + .unwrap(); // Outputs let mut outputs = wallet.get_asset_outputs_for_amount( @@ -988,7 +992,10 @@ mod outputs { *provider.base_asset_id(), predicate_coin_amount, ); - outputs.push(SdkOutput::contract_created(contract.contract_id(), contract.state_root())); + outputs.push(SdkOutput::contract_created( + contract.contract_id(), + contract.state_root(), + )); let mut tb = tb.with_inputs(inputs).with_outputs(outputs); @@ -1011,7 +1018,10 @@ mod outputs { assert!(instance.methods().get_output_type(0).call().await.is_ok()); // Verify predicate funds transferred - let predicate_balance = predicate.get_asset_balance(&AssetId::default()).await.unwrap(); + let predicate_balance = predicate + .get_asset_balance(&AssetId::default()) + .await + .unwrap(); assert_eq!(predicate_balance, 0); } From bab7dac0bb8ac84e197bb28b890168173b62dd35 Mon Sep 17 00:00:00 2001 From: bitzoic Date: Fri, 9 Aug 2024 16:51:07 +0700 Subject: [PATCH 05/10] Fix inline docs and comments --- sway-lib-std/src/auth.sw | 24 ++++++++++-------------- sway-lib-std/src/inputs.sw | 13 +++---------- 2 files changed, 13 insertions(+), 24 deletions(-) diff --git a/sway-lib-std/src/auth.sw b/sway-lib-std/src/auth.sw index 35b6b3fb47a..b474f2692f2 100644 --- a/sway-lib-std/src/auth.sw +++ b/sway-lib-std/src/auth.sw @@ -142,17 +142,17 @@ pub fn msg_sender() -> Result { pub fn caller_address() -> Result { let inputs = input_count().as_u64(); let mut candidate = None; - let mut itter = 0; + let mut iter = 0; // Note: `inputs_count` is guaranteed to be at least 1 for any valid tx. - while itter < inputs { - let type_of_input = input_type(itter); + while iter < inputs { + let type_of_input = input_type(iter); match type_of_input { Some(Input::Coin) => (), Some(Input::Message) => (), _ => { // type != InputCoin or InputMessage, continue looping. - itter += 1; + iter += 1; continue; } } @@ -160,14 +160,14 @@ pub fn caller_address() -> Result { // type == InputCoin or InputMessage. let owner_of_input = match type_of_input { Some(Input::Coin) => { - input_coin_owner(itter) + input_coin_owner(iter) }, Some(Input::Message) => { - input_message_sender(itter) + input_message_sender(iter) }, _ => { // type != InputCoin or InputMessage, continue looping. - itter += 1; + iter += 1; continue; } }; @@ -175,7 +175,7 @@ pub fn caller_address() -> Result { if candidate.is_none() { // This is the first input seen of the correct type. candidate = owner_of_input; - itter += 1; + iter += 1; continue; } @@ -184,7 +184,7 @@ pub fn caller_address() -> Result { // at this point, so we can unwrap safely. if owner_of_input.unwrap() == candidate.unwrap() { // Owners are a match, continue looping. - itter += 1; + iter += 1; continue; } @@ -205,17 +205,13 @@ pub fn caller_address() -> Result { /// /// * [Option
] - The address of this predicate. /// -/// # Reverts -/// -/// * When called outside of a predicate program. -/// /// # Examples /// /// ```sway /// use std::auth::predicate_address; /// /// fn main() { -/// let this_predicate = predicate_address(); +/// let this_predicate = predicate_address().unwrap(); /// log(this_predicate); /// } /// ``` diff --git a/sway-lib-std/src/inputs.sw b/sway-lib-std/src/inputs.sw index 69e87a77fa3..34b9df9f565 100644 --- a/sway-lib-std/src/inputs.sw +++ b/sway-lib-std/src/inputs.sw @@ -9,7 +9,6 @@ use ::asset_id::AssetId; use ::bytes::Bytes; use ::contract_id::ContractId; use ::option::Option::{self, *}; -use ::revert::revert; use ::tx::{ GTF_CREATE_INPUT_AT_INDEX, GTF_CREATE_INPUTS_COUNT, @@ -251,8 +250,8 @@ pub fn input_predicate_data_pointer(index: u64) -> Option { /// use std::inputs::input_predicate_data; /// /// fn foo() { -/// let input_predicate_data: u64 = input_predicate_data(0); -/// assert(input_predicate_data == 100); +/// let result_input_predicate_data: u64 = input_predicate_data::(0).unwrap(); +/// assert(result_input_predicate_data == 100); /// } /// ``` pub fn input_predicate_data(index: u64) -> Option @@ -443,8 +442,6 @@ pub fn input_predicate_data_length(index: u64) -> Option { } } -// Coin Inputs - /// Gets the sender of the input message at `index`. /// /// # Arguments @@ -559,11 +556,7 @@ pub fn input_message_data_length(index: u64) -> Option { /// /// # Returns /// -/// * [Option(Bytes)] - The data of the input message at `index`, if the input's type is `Input::Message`. -/// -/// # Reverts -/// -/// * When the input's type is not `Input::Message`. +/// * [Option] - The data of the input message at `index`, if the input's type is `Input::Message`. /// /// # Examples /// From ecf765db762d0b1a4e31a02c51002ad78e32b24b Mon Sep 17 00:00:00 2001 From: bitzoic Date: Mon, 12 Aug 2024 13:36:09 +0700 Subject: [PATCH 06/10] Add tests to ensure None is returned --- sway-lib-std/src/inputs.sw | 25 ++- .../test_artifacts/tx_contract/src/main.sw | 56 +++---- .../src/sdk-harness/test_projects/auth/mod.rs | 4 +- .../test_projects/tx_fields/mod.rs | 149 ++++++++++++++++-- 4 files changed, 187 insertions(+), 47 deletions(-) diff --git a/sway-lib-std/src/inputs.sw b/sway-lib-std/src/inputs.sw index 34b9df9f565..a9973e87c7c 100644 --- a/sway-lib-std/src/inputs.sw +++ b/sway-lib-std/src/inputs.sw @@ -95,6 +95,10 @@ impl Eq for Input { /// } /// ``` pub fn input_type(index: u64) -> Option { + if index >= input_count().as_u64() { + return None + } + match __gtf::(index, GTF_INPUT_TYPE) { 0u8 => Some(Input::Coin), 1u8 => Some(Input::Contract), @@ -134,7 +138,7 @@ pub fn input_count() -> u16 { /// /// # Returns /// -/// * [u64] - The pointer of the input at `index`. +/// * [Option] - The pointer of the input at `index`. /// /// # Examples /// @@ -142,13 +146,17 @@ pub fn input_count() -> u16 { /// use std::inputs::input_pointer; /// /// fn foo() { -/// let input_pointer = input_pointer(0); +/// let input_pointer = input_pointer(0).unwrap(); /// } /// ``` -pub fn input_pointer(index: u64) -> u64 { +pub fn input_pointer(index: u64) -> Option { + if index >= input_count().as_u64() { + return None + } + match tx_type() { - Transaction::Script => __gtf::(index, GTF_SCRIPT_INPUT_AT_INDEX), - Transaction::Create => __gtf::(index, GTF_CREATE_INPUT_AT_INDEX), + Transaction::Script => Some(__gtf::(index, GTF_SCRIPT_INPUT_AT_INDEX)), + Transaction::Create => Some(__gtf::(index, GTF_CREATE_INPUT_AT_INDEX)), } } @@ -516,8 +524,11 @@ pub fn input_message_recipient(index: u64) -> Option
{ /// assert(input_message_nonce != b256::zero()); /// } /// ``` -pub fn input_message_nonce(index: u64) -> b256 { - __gtf::(index, GTF_INPUT_MESSAGE_NONCE) +pub fn input_message_nonce(index: u64) -> Option { + match input_type(index) { + Some(Input::Message) => Some(__gtf::(index, GTF_INPUT_MESSAGE_NONCE)), + _ => None, + } } /// Gets the length of the input message at `index`. 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 9c58dca0567..51a778deb8f 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 @@ -35,17 +35,17 @@ abi TxContractTest { fn get_tx_script_bytecode_hash() -> b256; fn get_input_type(index: u64) -> Option; - fn get_tx_input_pointer(index: u64) -> u64; - fn get_input_coin_owner(index: u64) -> Address; - fn get_input_amount(index: u64) -> u64; + fn get_tx_input_pointer(index: u64) -> Option; + fn get_input_coin_owner(index: u64) -> Option
; + fn get_input_amount(index: u64) -> Option; fn get_tx_input_predicate_data_pointer(index: u64) -> u64; - fn get_input_message_sender(index: u64) -> Address; - fn get_input_message_recipient(index: u64) -> Address; - fn get_input_message_nonce(index: u64) -> b256; - fn get_input_witness_index(index: u64) -> u16; - fn get_input_message_data_length(index: u64) -> u64; - fn get_input_predicate_length(index: u64) -> u64; - fn get_input_predicate_data_length(index: u64) -> u64; + fn get_input_message_sender(index: u64) -> Option
; + fn get_input_message_recipient(index: u64) -> Option
; + fn get_input_message_nonce(index: u64) -> Option; + fn get_input_witness_index(index: u64) -> Option; + 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_predicate(index: u64, bytecode: Vec) -> bool; @@ -113,43 +113,43 @@ impl TxContractTest for Contract { fn get_tx_script_bytecode_hash() -> b256 { tx_script_bytecode_hash() } - fn get_tx_input_pointer(index: u64) -> u64 { + fn get_tx_input_pointer(index: u64) -> Option { input_pointer(index) } fn get_input_type(index: u64) -> Option { input_type(index) } - fn get_input_coin_owner(index: u64) -> Address { - input_coin_owner(index).unwrap() + fn get_input_coin_owner(index: u64) -> Option
{ + input_coin_owner(index) } - fn get_input_amount(index: u64) -> u64 { - input_amount(index).unwrap() + fn get_input_amount(index: u64) -> Option { + input_amount(index) } fn get_tx_input_predicate_data_pointer(index: u64) -> u64 { asm(r1: input_predicate_data_pointer(index).unwrap()) { r1: u64 } } - fn get_input_message_sender(index: u64) -> Address { - input_message_sender(index).unwrap() + fn get_input_message_sender(index: u64) -> Option
{ + input_message_sender(index) } - fn get_input_message_recipient(index: u64) -> Address { - input_message_recipient(index).unwrap() + fn get_input_message_recipient(index: u64) -> Option
{ + input_message_recipient(index) } - fn get_input_message_nonce(index: u64) -> b256 { + fn get_input_message_nonce(index: u64) -> Option { input_message_nonce(index) } - fn get_input_witness_index(index: u64) -> u16 { - input_witness_index(index).unwrap() + fn get_input_witness_index(index: u64) -> Option { + input_witness_index(index) } - fn get_input_message_data_length(index: u64) -> u64 { - input_message_data_length(index).unwrap() + fn get_input_message_data_length(index: u64) -> Option { + input_message_data_length(index) } - fn get_input_predicate_length(index: u64) -> u64 { - input_predicate_length(index).unwrap() + fn get_input_predicate_length(index: u64) -> Option { + input_predicate_length(index) } - fn get_input_predicate_data_length(index: u64) -> u64 { - input_predicate_data_length(index).unwrap() + 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 { let data = match input_message_data(index, offset) { diff --git a/test/src/sdk-harness/test_projects/auth/mod.rs b/test/src/sdk-harness/test_projects/auth/mod.rs index fcbfd2766eb..ba9e2c654b6 100644 --- a/test/src/sdk-harness/test_projects/auth/mod.rs +++ b/test/src/sdk-harness/test_projects/auth/mod.rs @@ -196,7 +196,7 @@ async fn can_get_predicate_address() { // Setup predicate. let hex_predicate_address: &str = - "0xd7c64424d48025fa6047a7508c30c2ea3a7c126e6efcc93f6195f21a48742a1f"; + "0x421ed9a7b208036e67dc95b7f0c0ae085f5c0b3ee55af9719d146ea6a59e0716"; let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string"); let predicate_bech32_address = Bech32Address::from(predicate_address); @@ -322,7 +322,7 @@ async fn when_incorrect_predicate_address_passed() { async fn can_get_predicate_address_in_message() { // Setup predicate address. let hex_predicate_address: &str = - "0xd7c64424d48025fa6047a7508c30c2ea3a7c126e6efcc93f6195f21a48742a1f"; + "0x421ed9a7b208036e67dc95b7f0c0ae085f5c0b3ee55af9719d146ea6a59e0716"; let predicate_address = Address::from_str(hex_predicate_address).expect("failed to create Address from string"); let predicate_bech32_address = Bech32Address::from(predicate_address); 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 a481af9064f..9b534cbb1ab 100644 --- a/test/src/sdk-harness/test_projects/tx_fields/mod.rs +++ b/test/src/sdk-harness/test_projects/tx_fields/mod.rs @@ -530,6 +530,15 @@ mod inputs { .await .unwrap(); assert_eq!(result.value, Some(Input::Coin)); + + // Assert invalid index returns None + let result = contract_instance + .methods() + .get_input_type(2) + .call() + .await + .unwrap(); + assert_eq!(result.value, None); } #[tokio::test] @@ -543,7 +552,17 @@ mod inputs { .await .unwrap(); - assert_eq!(result.value, default_amount); + assert_eq!(result.value, Some(default_amount)); + + // Assert invalid index returns None + let result = contract_instance + .methods() + .get_input_amount(2) + .call() + .await + .unwrap(); + + assert_eq!(result.value, None); } #[tokio::test] @@ -557,7 +576,17 @@ mod inputs { .await .unwrap(); - assert_eq!(owner_result.value, deployment_wallet.address().into()); + assert_eq!(owner_result.value, Some(deployment_wallet.address().into())); + + // Assert invalid index returns None + let result = contract_instance + .methods() + .get_input_coin_owner(2) + .call() + .await + .unwrap(); + + assert_eq!(result.value, None); } #[tokio::test] @@ -589,6 +618,16 @@ mod inputs { .take_receipts_checked(None) .unwrap(); assert_eq!(receipts[1].data(), Some(&[1u8][..])); + + // Assert invalid index returns None + let result = contract_instance + .methods() + .get_input_predicate(3, predicate_bytes.clone()) + .call() + .await + .unwrap(); + + assert_eq!(result.value, false); } mod message { @@ -627,7 +666,17 @@ mod inputs { .take_receipts_checked(None) .unwrap(); - assert_eq!(receipts[1].data().unwrap(), *message.sender.hash()); + assert_eq!(receipts[1].data().unwrap()[8..40], *message.sender.hash()); + + // Assert none returned when transaction type is not a message + let none_result = contract_instance + .methods() + .get_input_message_sender(0) + .call() + .await + .unwrap(); + + assert_eq!(none_result.value, None); } #[tokio::test] @@ -663,7 +712,17 @@ mod inputs { .take_receipts_checked(None) .unwrap(); - assert_eq!(receipts[1].data().unwrap(), recipient.as_slice()); + assert_eq!(receipts[1].data().unwrap()[8..40], *recipient.as_slice()); + + // Assert none returned when transaction type is not a message + let none_result = contract_instance + .methods() + .get_input_message_recipient(0) + .call() + .await + .unwrap(); + + assert_eq!(none_result.value, None); } #[tokio::test] @@ -700,7 +759,17 @@ mod inputs { .take_receipts_checked(None) .unwrap(); - assert_eq!(receipts[1].data().unwrap(), nonce.as_slice()); + assert_eq!(receipts[1].data().unwrap()[8..40], *nonce.as_slice()); + + // Assert none returned when transaction type is not a message + let none_result = contract_instance + .methods() + .get_input_message_nonce(0) + .call() + .await + .unwrap(); + + assert_eq!(none_result.value, None); } #[tokio::test] @@ -713,7 +782,17 @@ mod inputs { .await .unwrap(); - assert_eq!(result.value, 0); + assert_eq!(result.value, Some(0)); + + // Assert none returned when not a valid index + let none_result = contract_instance + .methods() + .get_input_witness_index(3) + .call() + .await + .unwrap(); + + assert_eq!(none_result.value, None); } #[tokio::test] @@ -748,7 +827,17 @@ mod inputs { .take_receipts_checked(None) .unwrap(); - assert_eq!(receipts[1].data(), Some(&[0, 0, 0, 0, 0, 0, 0, 3][..])); + assert_eq!(receipts[1].data(), Some(&[0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 3][..])); + + // Assert none returned when transaction type is not a message + let none_result = contract_instance + .methods() + .get_input_message_data_length(0) + .call() + .await + .unwrap(); + + assert_eq!(none_result.value, None); } #[tokio::test] @@ -784,7 +873,17 @@ mod inputs { .unwrap(); let len = predicate_bytecode.len() as u64; - assert_eq!(receipts[1].data(), Some(len.to_be_bytes().as_slice())); + assert_eq!(receipts[1].data().unwrap()[8..16], *len.to_be_bytes().as_slice()); + + // Assert none returned when index is invalid + let none_result = contract_instance + .methods() + .get_input_predicate_length(3) + .call() + .await + .unwrap(); + + assert_eq!(none_result.value, None); } #[tokio::test] @@ -818,7 +917,17 @@ mod inputs { .take_receipts_checked(None) .unwrap(); - assert_eq!(receipts[1].data(), Some(0u64.to_le_bytes().as_slice())); + assert_eq!(receipts[1].data().unwrap()[8..16], *0u64.to_le_bytes().as_slice()); + + // Assert none returned when transaction type is not a message + let none_result = contract_instance + .methods() + .get_input_predicate_data_length(0) + .call() + .await + .unwrap(); + + assert_eq!(none_result.value, None); } #[tokio::test] @@ -855,6 +964,16 @@ mod inputs { .unwrap(); assert_eq!(receipts[1].data(), Some(&[1][..])); + + // Assert none returned when transaction type is not a message + let none_result = contract_instance + .methods() + .get_input_message_data(3, 0, MESSAGE_DATA) + .call() + .await + .unwrap(); + + assert_eq!(none_result.value, false); } #[tokio::test] @@ -866,7 +985,7 @@ mod inputs { let handler = contract_instance .methods() - .get_input_predicate(3, predicate_bytecode); + .get_input_predicate(3, predicate_bytecode.clone()); let mut builder = handler.transaction_builder().await.unwrap(); @@ -888,6 +1007,16 @@ mod inputs { .unwrap(); assert_eq!(receipts[1].data(), Some(1u8.to_le_bytes().as_slice())); + + // Assert none returned when index is invalid + let none_result = contract_instance + .methods() + .get_input_predicate(3, predicate_bytecode) + .call() + .await + .unwrap(); + + assert_eq!(none_result.value, false); } } } From a0f407b077ff3ad2fbdd9c74ff208995fe0a0f90 Mon Sep 17 00:00:00 2001 From: bitzoic Date: Thu, 15 Aug 2024 12:53:32 +0700 Subject: [PATCH 07/10] Update inputs_pointer to use raw_ptr --- sway-lib-std/src/inputs.sw | 8 ++++---- .../sdk-harness/test_artifacts/tx_contract/src/main.sw | 7 ++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/sway-lib-std/src/inputs.sw b/sway-lib-std/src/inputs.sw index a9973e87c7c..e4800b7ef02 100644 --- a/sway-lib-std/src/inputs.sw +++ b/sway-lib-std/src/inputs.sw @@ -138,7 +138,7 @@ pub fn input_count() -> u16 { /// /// # Returns /// -/// * [Option] - The pointer of the input at `index`. +/// * [Option] - The pointer of the input at `index`. /// /// # Examples /// @@ -149,14 +149,14 @@ pub fn input_count() -> u16 { /// let input_pointer = input_pointer(0).unwrap(); /// } /// ``` -pub fn input_pointer(index: u64) -> Option { +pub fn input_pointer(index: u64) -> Option { if index >= input_count().as_u64() { return None } match tx_type() { - Transaction::Script => Some(__gtf::(index, GTF_SCRIPT_INPUT_AT_INDEX)), - Transaction::Create => Some(__gtf::(index, GTF_CREATE_INPUT_AT_INDEX)), + Transaction::Script => Some(__gtf::(index, GTF_SCRIPT_INPUT_AT_INDEX)), + Transaction::Create => Some(__gtf::(index, GTF_CREATE_INPUT_AT_INDEX)), } } 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 51a778deb8f..1b5bfa3e83c 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 @@ -114,7 +114,12 @@ impl TxContractTest for Contract { tx_script_bytecode_hash() } fn get_tx_input_pointer(index: u64) -> Option { - input_pointer(index) + let ptr = input_pointer(index); + if ptr.is_none() { + return None + } + + Some(asm (r1: ptr) { r1: u64 }) } fn get_input_type(index: u64) -> Option { input_type(index) From dd90db2f892ce0dfd7d51c12b60e11c501e2c8c8 Mon Sep 17 00:00:00 2001 From: bitzoic Date: Fri, 16 Aug 2024 13:39:57 +0700 Subject: [PATCH 08/10] Resolve PR comments --- sway-lib-std/src/inputs.sw | 4 +- sway-lib-std/src/u128.sw | 131 +++++++++++++++++++------------------ 2 files changed, 71 insertions(+), 64 deletions(-) diff --git a/sway-lib-std/src/inputs.sw b/sway-lib-std/src/inputs.sw index e4800b7ef02..2dd4cb91791 100644 --- a/sway-lib-std/src/inputs.sw +++ b/sway-lib-std/src/inputs.sw @@ -258,8 +258,8 @@ pub fn input_predicate_data_pointer(index: u64) -> Option { /// use std::inputs::input_predicate_data; /// /// fn foo() { -/// let result_input_predicate_data: u64 = input_predicate_data::(0).unwrap(); -/// assert(result_input_predicate_data == 100); +/// let input_predicate_data: u64 = input_predicate_data::(0).unwrap(); +/// assert(input_predicate_data == 100); /// } /// ``` pub fn input_predicate_data(index: u64) -> Option diff --git a/sway-lib-std/src/u128.sw b/sway-lib-std/src/u128.sw index 94a27c98027..3e5aa32571c 100644 --- a/sway-lib-std/src/u128.sw +++ b/sway-lib-std/src/u128.sw @@ -548,24 +548,26 @@ impl core::ops::Not for U128 { impl core::ops::Add for U128 { /// Add a `U128` to a `U128`. Reverts on overflow. fn add(self, other: Self) -> Self { - let mut upper_128 = self.upper.overflowing_add(other.upper); + let self_parts = (0, 0, self.upper, self.lower); + let other_parts = (0, 0, other.upper, other.lower); - // If the upper overflows, then the number cannot fit in 128 bits, so panic. - assert(upper_128.upper == 0); - let lower_128 = self.lower.overflowing_add(other.lower); + let self_u256 = asm(r1: self_parts) { + r1: u256 + }; + let other_u256 = asm(r1: other_parts) { + r1: u256 + }; - // If overflow has occurred in the lower component addition, carry. - // Note: carry can be at most 1. - if lower_128.upper > 0 { - upper_128 = upper_128.lower.overflowing_add(lower_128.upper); - } + let res_u256 = self_u256 + other_u256; + let res_parts = asm(r1: res_u256) { + r1: (u64, u64, u64, u64) + }; - // If overflow has occurred in the upper component addition, panic. - assert(upper_128.upper == 0); + //assert(res_parts.0 == 0 && res_parts.1 == 0); Self { - upper: upper_128.lower, - lower: lower_128.lower, + upper: res_parts.2, + lower: res_parts.3, } } } @@ -573,75 +575,80 @@ impl core::ops::Add for U128 { impl core::ops::Subtract for U128 { /// Subtract a `U128` from a `U128`. Reverts of overflow. fn subtract(self, other: Self) -> Self { - // If trying to subtract a larger number, panic. - assert(!(self < other)); + let self_parts = (0, 0, self.upper, self.lower); + let other_parts = (0, 0, other.upper, other.lower); - let mut upper = self.upper - other.upper; - let mut lower = 0; + let self_u256 = asm(r1: self_parts) { + r1: u256 + }; + let other_u256 = asm(r1: other_parts) { + r1: u256 + }; - // If necessary, borrow and carry for lower subtraction - if self.lower < other.lower { - lower = u64::max() - (other.lower - self.lower - 1); - upper -= 1; - } else { - lower = self.lower - other.lower; - } + let res_u256 = self_u256 - other_u256; + let res_parts = asm(r1: res_u256) { + r1: (u64, u64, u64, u64) + }; + + //assert(res_parts.0 == 0 && res_parts.1 == 0); - Self { upper, lower } + Self { + upper: res_parts.2, + lower: res_parts.3, + } } } impl core::ops::Multiply for U128 { /// Multiply a `U128` with a `U128`. Reverts of overflow. fn multiply(self, other: Self) -> Self { - // in case both of the `U128` upper parts are bigger than zero, - // it automatically means overflow, as any `U128` value - // is upper part multiplied by 2 ^ 64 + lower part - assert(self.upper == 0 || other.upper == 0); - - let mut result = self.lower.overflowing_mul(other.lower); - if self.upper == 0 { - // panic in case of overflow - result.upper += self.lower * other.upper; - } else if other.upper == 0 { - // panic in case of overflow - result.upper += self.upper * other.lower; - } + let self_parts = (0, 0, self.upper, self.lower); + let other_parts = (0, 0, other.upper, other.lower); - result + let self_u256 = asm(r1: self_parts) { + r1: u256 + }; + let other_u256 = asm(r1: other_parts) { + r1: u256 + }; + + let res_u256 = self_u256 * other_u256; + let res_parts = asm(r1: res_u256) { + r1: (u64, u64, u64, u64) + }; + + //assert(res_parts.0 == 0 && res_parts.1 == 0); + + Self { + upper: res_parts.2, + lower: res_parts.3, + } } } impl core::ops::Divide for U128 { /// Divide a `U128` by a `U128`. Reverts if divisor is zero. fn divide(self, divisor: Self) -> Self { - let zero = Self::from((0, 0)); - - assert(divisor != zero); + let self_parts = (0, 0, self.upper, self.lower); + let divisor_parts = (0, 0, divisor.upper, divisor.lower); - if self.upper == 0 && divisor.upper == 0 { - return Self::from((0, self.lower / divisor.lower)); - } + let self_u256 = asm(r1: self_parts) { + r1: u256 + }; + let divisor_u256 = asm(r1: divisor_parts) { + r1: u256 + }; - let mut quotient = Self::new(); - let mut remainder = Self::new(); - let mut i = 128 - 1; - while true { - quotient <<= 1; - remainder <<= 1; - remainder.lower = remainder.lower | (self >> i).lower & 1; - if remainder >= divisor { - remainder -= divisor; - quotient.lower = quotient.lower | 1; - } + let res_u256 = self_u256 / divisor_u256; + let res_parts = asm(r1: res_u256) { + r1: (u64, u64, u64, u64) + }; - if i == 0 { - break; - } + //assert(res_parts.0 == 0 && res_parts.1 == 0); - i -= 1; + Self { + upper: res_parts.2, + lower: res_parts.3, } - - quotient } } From 3bc6f48953f126b7547b1d31e4b925f623fecfb9 Mon Sep 17 00:00:00 2001 From: bitzoic Date: Fri, 16 Aug 2024 14:44:58 +0700 Subject: [PATCH 09/10] Make pointer return functions private --- sway-lib-std/src/inputs.sw | 8 ++++--- .../test_artifacts/tx_contract/src/main.sw | 15 ------------ .../test_projects/tx_fields/mod.rs | 23 ------------------- 3 files changed, 5 insertions(+), 41 deletions(-) diff --git a/sway-lib-std/src/inputs.sw b/sway-lib-std/src/inputs.sw index 2dd4cb91791..00174fb194e 100644 --- a/sway-lib-std/src/inputs.sw +++ b/sway-lib-std/src/inputs.sw @@ -149,7 +149,8 @@ pub fn input_count() -> u16 { /// let input_pointer = input_pointer(0).unwrap(); /// } /// ``` -pub fn input_pointer(index: u64) -> Option { +#[allow(dead_code)] +fn input_pointer(index: u64) -> Option { if index >= input_count().as_u64() { return None } @@ -234,7 +235,8 @@ pub fn input_coin_owner(index: u64) -> Option
{ /// let input_predicate_data_pointer = input_predicate_data_pointer(0); /// assert(input_predicate_data_pointer.is_some()); // Ensure the input is a coin or message input. /// } -pub fn input_predicate_data_pointer(index: u64) -> Option { +#[allow(dead_code)] +fn input_predicate_data_pointer(index: u64) -> Option { match input_type(index) { Some(Input::Coin) => Some(__gtf::(index, GTF_INPUT_COIN_PREDICATE_DATA)), Some(Input::Message) => Some(__gtf::(index, GTF_INPUT_MESSAGE_PREDICATE_DATA)), @@ -377,7 +379,7 @@ pub fn input_predicate_length(index: u64) -> Option { /// assert(input_predicate_pointer.is_some()); /// } /// ``` -pub fn input_predicate_pointer(index: u64) -> Option { +fn input_predicate_pointer(index: u64) -> Option { match input_type(index) { Some(Input::Coin) => Some(__gtf::(index, GTF_INPUT_COIN_PREDICATE)), Some(Input::Message) => Some(__gtf::(index, GTF_INPUT_MESSAGE_PREDICATE)), 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 1b5bfa3e83c..1be7402bf12 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 @@ -35,10 +35,8 @@ abi TxContractTest { fn get_tx_script_bytecode_hash() -> b256; fn get_input_type(index: u64) -> Option; - fn get_tx_input_pointer(index: u64) -> Option; fn get_input_coin_owner(index: u64) -> Option
; fn get_input_amount(index: u64) -> Option; - fn get_tx_input_predicate_data_pointer(index: u64) -> u64; fn get_input_message_sender(index: u64) -> Option
; fn get_input_message_recipient(index: u64) -> Option
; fn get_input_message_nonce(index: u64) -> Option; @@ -113,14 +111,6 @@ impl TxContractTest for Contract { fn get_tx_script_bytecode_hash() -> b256 { tx_script_bytecode_hash() } - fn get_tx_input_pointer(index: u64) -> Option { - let ptr = input_pointer(index); - if ptr.is_none() { - return None - } - - Some(asm (r1: ptr) { r1: u64 }) - } fn get_input_type(index: u64) -> Option { input_type(index) } @@ -130,11 +120,6 @@ impl TxContractTest for Contract { fn get_input_amount(index: u64) -> Option { input_amount(index) } - fn get_tx_input_predicate_data_pointer(index: u64) -> u64 { - asm(r1: input_predicate_data_pointer(index).unwrap()) { - r1: u64 - } - } fn get_input_message_sender(index: u64) -> Option
{ input_message_sender(index) } 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 ac17ca4a421..12251d42da6 100644 --- a/test/src/sdk-harness/test_projects/tx_fields/mod.rs +++ b/test/src/sdk-harness/test_projects/tx_fields/mod.rs @@ -485,29 +485,6 @@ mod tx { mod inputs { use super::*; - mod revert { - use super::*; - - mod contract { - use super::*; - - #[tokio::test] - #[should_panic(expected = "Revert(0)")] - async fn fails_to_get_predicate_data_pointer_from_input_contract() { - let (contract_instance, _, _, _) = get_contracts(true).await; - let call_params = CallParameters::default(); - contract_instance - .methods() - .get_tx_input_predicate_data_pointer(0) - .call_params(call_params) - .unwrap() - .call() - .await - .unwrap(); - } - } - } - mod success { use super::*; From a19a5f605f8c1c67123cba43128ac7473adab46a Mon Sep 17 00:00:00 2001 From: bitzoic Date: Fri, 16 Aug 2024 14:55:47 +0700 Subject: [PATCH 10/10] Revert U128 changes --- sway-lib-std/src/u128.sw | 131 ++++++++++++++++++--------------------- 1 file changed, 62 insertions(+), 69 deletions(-) diff --git a/sway-lib-std/src/u128.sw b/sway-lib-std/src/u128.sw index 3e5aa32571c..94a27c98027 100644 --- a/sway-lib-std/src/u128.sw +++ b/sway-lib-std/src/u128.sw @@ -548,26 +548,24 @@ impl core::ops::Not for U128 { impl core::ops::Add for U128 { /// Add a `U128` to a `U128`. Reverts on overflow. fn add(self, other: Self) -> Self { - let self_parts = (0, 0, self.upper, self.lower); - let other_parts = (0, 0, other.upper, other.lower); + let mut upper_128 = self.upper.overflowing_add(other.upper); - let self_u256 = asm(r1: self_parts) { - r1: u256 - }; - let other_u256 = asm(r1: other_parts) { - r1: u256 - }; + // If the upper overflows, then the number cannot fit in 128 bits, so panic. + assert(upper_128.upper == 0); + let lower_128 = self.lower.overflowing_add(other.lower); - let res_u256 = self_u256 + other_u256; - let res_parts = asm(r1: res_u256) { - r1: (u64, u64, u64, u64) - }; + // If overflow has occurred in the lower component addition, carry. + // Note: carry can be at most 1. + if lower_128.upper > 0 { + upper_128 = upper_128.lower.overflowing_add(lower_128.upper); + } - //assert(res_parts.0 == 0 && res_parts.1 == 0); + // If overflow has occurred in the upper component addition, panic. + assert(upper_128.upper == 0); Self { - upper: res_parts.2, - lower: res_parts.3, + upper: upper_128.lower, + lower: lower_128.lower, } } } @@ -575,80 +573,75 @@ impl core::ops::Add for U128 { impl core::ops::Subtract for U128 { /// Subtract a `U128` from a `U128`. Reverts of overflow. fn subtract(self, other: Self) -> Self { - let self_parts = (0, 0, self.upper, self.lower); - let other_parts = (0, 0, other.upper, other.lower); - - let self_u256 = asm(r1: self_parts) { - r1: u256 - }; - let other_u256 = asm(r1: other_parts) { - r1: u256 - }; - - let res_u256 = self_u256 - other_u256; - let res_parts = asm(r1: res_u256) { - r1: (u64, u64, u64, u64) - }; + // If trying to subtract a larger number, panic. + assert(!(self < other)); - //assert(res_parts.0 == 0 && res_parts.1 == 0); + let mut upper = self.upper - other.upper; + let mut lower = 0; - Self { - upper: res_parts.2, - lower: res_parts.3, + // If necessary, borrow and carry for lower subtraction + if self.lower < other.lower { + lower = u64::max() - (other.lower - self.lower - 1); + upper -= 1; + } else { + lower = self.lower - other.lower; } + + Self { upper, lower } } } impl core::ops::Multiply for U128 { /// Multiply a `U128` with a `U128`. Reverts of overflow. fn multiply(self, other: Self) -> Self { - let self_parts = (0, 0, self.upper, self.lower); - let other_parts = (0, 0, other.upper, other.lower); - - let self_u256 = asm(r1: self_parts) { - r1: u256 - }; - let other_u256 = asm(r1: other_parts) { - r1: u256 - }; - - let res_u256 = self_u256 * other_u256; - let res_parts = asm(r1: res_u256) { - r1: (u64, u64, u64, u64) - }; - - //assert(res_parts.0 == 0 && res_parts.1 == 0); - - Self { - upper: res_parts.2, - lower: res_parts.3, + // in case both of the `U128` upper parts are bigger than zero, + // it automatically means overflow, as any `U128` value + // is upper part multiplied by 2 ^ 64 + lower part + assert(self.upper == 0 || other.upper == 0); + + let mut result = self.lower.overflowing_mul(other.lower); + if self.upper == 0 { + // panic in case of overflow + result.upper += self.lower * other.upper; + } else if other.upper == 0 { + // panic in case of overflow + result.upper += self.upper * other.lower; } + + result } } impl core::ops::Divide for U128 { /// Divide a `U128` by a `U128`. Reverts if divisor is zero. fn divide(self, divisor: Self) -> Self { - let self_parts = (0, 0, self.upper, self.lower); - let divisor_parts = (0, 0, divisor.upper, divisor.lower); + let zero = Self::from((0, 0)); - let self_u256 = asm(r1: self_parts) { - r1: u256 - }; - let divisor_u256 = asm(r1: divisor_parts) { - r1: u256 - }; + assert(divisor != zero); - let res_u256 = self_u256 / divisor_u256; - let res_parts = asm(r1: res_u256) { - r1: (u64, u64, u64, u64) - }; + if self.upper == 0 && divisor.upper == 0 { + return Self::from((0, self.lower / divisor.lower)); + } + + let mut quotient = Self::new(); + let mut remainder = Self::new(); + let mut i = 128 - 1; + while true { + quotient <<= 1; + remainder <<= 1; + remainder.lower = remainder.lower | (self >> i).lower & 1; + if remainder >= divisor { + remainder -= divisor; + quotient.lower = quotient.lower | 1; + } - //assert(res_parts.0 == 0 && res_parts.1 == 0); + if i == 0 { + break; + } - Self { - upper: res_parts.2, - lower: res_parts.3, + i -= 1; } + + quotient } }