Skip to content

Commit

Permalink
Increase Safety when introspecting transaction inputs (#6405)
Browse files Browse the repository at this point in the history
## Description

When using the `inputs.sw` library of the std-lib, if a bad input was
given to the functions or a transaction did not exist, the functions
would revert. Instead, they now return options so error may be caught.

## Fixes

- `input_pointer` now returns a pointer over a `u64` and is private.

## Breaking

There are a number of breaking changes in function return types.

- `predicate_address()` now returns an `Option<Address>`.
Before:
```sway
let my_predicate_address: Address = predicate_address();
```
After
```sway
let my_predicate_address: Address = predicate_address().unwrap();
```

- `input_type()` now returns an `Option<Input>`.
Before:
```sway
let my_input_type: Input = input_type(0);
```
After:
```sway
let my_input_type: Input = input_type(0).unwrap();
```

- `input_predicate_data()` now returns an `Option<T>`.
Before:
```sway
let my_data: u64 = input_predicate_data::<u64>(0);
```
After:
```sway
let my_data: u64 = input_predicate_data::<u64>(0).unwrap();
```

- `input_predicate()` now returns an `Option<Bytes>`.
Before:
```sway
let my_input_predicate: Bytes = input_predicate(0);
```
After:
```sway
let my_input_predicate: Bytes = input_predicate(0).unwrap();
```

- `input_message_sender()` now returns an `Option<Address>`.
Before:
```sway
let my_message_sender: Address = input_message_sender(0);
```
After:
```sway
let my_message_sender: Address = input_message_sender(0).unwrap();
```

- `input_message_recipient()` now returns an `Option<Address>`.
Before:
```sway
let my_message_recipient: Address = input_message_recipient(0);
```
After:
```sway
let my_message_recipient: Address = input_message_recipient(0).unwrap();
```

- `input_message_data_length()` now returns an `Option<u64>`.
Before:
```sway
let my_message_data_length: u64 = input_message_data_length(0);
```
After:
```sway
let my_message_data_length: u64 = input_message_data_length(0).unwrap();
```

- `input_message_data()` now returns an `Option<Bytes>`.
Before:
```sway
let my_input_message_data: Bytes = input_message_data(0);
```
After:
```sway
let my_input_message_data: Bytes = input_message_data(0).unwrap();
```

- `input_pointer()` now returns an `Option<raw_ptr>` and is private
Before:
```sway
let my_input_pointer: u64 = input_pointer(0);
```
After:
```sway
let my_input_pointer: raw_ptr = input_pointer(0).unwrap();
```

- `input_message_nonce()` now returns an `Option<b256>`
Before:
```sway
let my_message_nonce: b256 = input_message_nonce(0);
```
After:
```sway
let my_message_nonce: b256 = input_message_nonce(0).unwrap();
```

Closes #6216 

## Checklist

- [x] I have linked to any relevant issues.
- [x] I have commented my code, particularly in hard-to-understand
areas.
- [x] I have updated the documentation where relevant (API docs, the
reference, and the Sway book).
- [ ] If my change requires substantial documentation changes, I have
[requested support from the DevRel
team](https://github.com/FuelLabs/devrel-requests/issues/new/choose)
- [x] I have added tests that prove my fix is effective or that my
feature works.
- [x] I have added (or requested a maintainer to add) the necessary
`Breaking*` or `New Feature` labels where relevant.
- [x] I have done my best to ensure that my PR adheres to [the Fuel Labs
Code Review
Standards](https://github.com/FuelLabs/rfcs/blob/master/text/code-standards/external-contributors.md).
- [x] I have requested a review from the relevant team or maintainers.

---------

Co-authored-by: K1-R1 <77465250+K1-R1@users.noreply.github.com>
  • Loading branch information
bitzoic and K1-R1 authored Aug 16, 2024
1 parent 33549ed commit 3700e3f
Show file tree
Hide file tree
Showing 8 changed files with 313 additions and 189 deletions.
44 changes: 20 additions & 24 deletions sway-lib-std/src/auth.sw
Original file line number Diff line number Diff line change
Expand Up @@ -140,42 +140,42 @@ pub fn msg_sender() -> Result<Identity, AuthError> {
/// }
/// ```
pub fn caller_address() -> Result<Address, AuthError> {
let inputs = input_count();
let inputs = input_count().as_u64();
let mut candidate = None;
let mut i = 0u16;
let mut iter = 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 iter < inputs {
let type_of_input = input_type(iter);
match type_of_input {
Input::Coin => (),
Input::Message => (),
Some(Input::Coin) => (),
Some(Input::Message) => (),
_ => {
// type != InputCoin or InputMessage, continue looping.
i += 1u16;
iter += 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(iter)
},
Input::Message => {
Some(input_message_sender(i.as_u64()))
Some(Input::Message) => {
input_message_sender(iter)
},
_ => {
// type != InputCoin or InputMessage, continue looping.
i += 1u16;
iter += 1;
continue;
}
};

if candidate.is_none() {
// This is the first input seen of the correct type.
candidate = owner_of_input;
i += 1u16;
iter += 1;
continue;
}

Expand All @@ -184,7 +184,7 @@ pub fn caller_address() -> Result<Address, AuthError> {
// at this point, so we can unwrap safely.
if owner_of_input.unwrap() == candidate.unwrap() {
// Owners are a match, continue looping.
i += 1u16;
iter += 1;
continue;
}

Expand All @@ -203,23 +203,19 @@ pub fn caller_address() -> Result<Address, AuthError> {
///
/// # Returns
///
/// * [Address] - The address of this predicate.
///
/// # Reverts
///
/// * When called outside of a predicate program.
/// * [Option<Address>] - The address of this predicate.
///
/// # Examples
///
/// ```sway
/// use std::auth::predicate_address;
///
/// fn main() {
/// let this_predicate = predicate_address();
/// let this_predicate = predicate_address().unwrap();
/// log(this_predicate);
/// }
/// ```
pub fn predicate_address() -> Address {
pub fn predicate_address() -> Option<Address> {
// Get index of current predicate.
// i3 = GM_GET_VERIFYING_PREDICATE
let predicate_index = asm(r1) {
Expand All @@ -230,10 +226,10 @@ 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),
Some(Input::Coin) => input_coin_owner(predicate_index),
Some(Input::Message) => input_message_recipient(predicate_index),
_ => {
revert(0)
None
}
}
}
Loading

0 comments on commit 3700e3f

Please sign in to comment.