Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase Safety when introspecting transactions #6418

Merged
merged 12 commits into from
Aug 16, 2024
164 changes: 77 additions & 87 deletions sway-lib-std/src/tx.sw
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@ pub fn tx_type() -> Transaction {
}

const TIP_POLICY: u32 = 1u32 << 0;
const MATURITY_POLICY: u32 = 1u32 << 1;
const WITNESS_LIMIT_POLICY: u32 = 1u32 << 2;
const WITNESS_LIMIT_POLICY: u32 = 1u32 << 1;
const MATURITY_POLICY: u32 = 1u32 << 2;
const MAX_FEE_POLICY: u32 = 1u32 << 3;

/// Returns policies bits. It can be used to identify which policies are set.
Expand Down Expand Up @@ -151,14 +151,14 @@ pub fn script_gas_limit() -> u64 {
/// use std::tx::tx_maturity;
///
/// fn foo() {
/// let maturity = tx_maturity();
/// let maturity = tx_maturity().unwrap();
/// log(maturity);
/// }
/// ```
pub fn tx_maturity() -> Option<u64> {
pub fn tx_maturity() -> Option<u32> {
let bits = policies();
if bits & MATURITY_POLICY > 0 {
Some(__gtf::<u64>(0, GTF_POLICY_MATURITY))
Some(__gtf::<u32>(0, GTF_POLICY_MATURITY))
} else {
None
}
Expand Down Expand Up @@ -218,26 +218,22 @@ pub fn tx_max_fee() -> Option<u64> {
///
/// # Returns
///
/// * [u64] - The script length for the transaction.
///
/// # Reverts
///
/// * When the transaction type is of type `Transaction::Create`.
/// * [Option<u64>] - The script length for the transaction.
///
/// # Examples
///
/// ```sway
/// use std::tx::tx_script_length;
///
/// fn foo() {
/// let script_length = tx_script_length();
/// let script_length = tx_script_length().unwrap();
/// assert(script_length > 0);
/// }
/// ```
pub fn tx_script_length() -> u64 {
pub fn tx_script_length() -> Option<u64> {
match tx_type() {
Transaction::Script => __gtf::<u64>(0, GTF_SCRIPT_SCRIPT_LENGTH),
Transaction::Create => revert(0),
Transaction::Script => Some(__gtf::<u64>(0, GTF_SCRIPT_SCRIPT_LENGTH)),
Transaction::Create => None,
}
}

Expand All @@ -247,24 +243,20 @@ pub fn tx_script_length() -> u64 {
///
/// * [u64] - The script data length for the transaction.
///
/// # Reverts
///
/// * When the transaction type is of type `Transaction::Create`.
///
/// # Examples
///
/// ```sway
/// use std::tx::tx_script_data_length;
///
/// fn foo() {
/// let script_data_length = tx_script_data_length();
/// let script_data_length = tx_script_data_length().unwrap();
/// assert(script_data_length > 0);
/// }
/// ```
pub fn tx_script_data_length() -> u64 {
pub fn tx_script_data_length() -> Option<u64> {
match tx_type() {
Transaction::Script => __gtf::<u64>(0, GTF_SCRIPT_SCRIPT_DATA_LENGTH),
Transaction::Create => revert(0),
Transaction::Script => Some(__gtf::<u64>(0, GTF_SCRIPT_SCRIPT_DATA_LENGTH)),
Transaction::Create => None,
}
}

Expand Down Expand Up @@ -299,22 +291,26 @@ pub fn tx_witnesses_count() -> u64 {
///
/// # Returns
///
/// * [u64] - The pointer to the witness at index `index`.
/// * [Option<raw_ptr>] - The pointer to the witness at index `index`.
///
/// # Examples
///
/// ```sway
/// use std::tx::tx_witness_pointer;
///
/// fn foo() {
/// let witness_pointer = tx_witness_pointer(0);
/// log(witness_pointer);
/// let witness_pointer = tx_witness_pointer(0).unwrap();
/// }
/// ```
pub fn tx_witness_pointer(index: u64) -> u64 {
#[allow(dead_code)]
fn tx_witness_pointer(index: u64) -> Option<raw_ptr> {
if index >= tx_witnesses_count() {
return None
}

match tx_type() {
Transaction::Script => __gtf::<u64>(index, GTF_SCRIPT_WITNESS_AT_INDEX),
Transaction::Create => __gtf::<u64>(index, GTF_CREATE_WITNESS_AT_INDEX),
Transaction::Script => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_WITNESS_AT_INDEX)),
Transaction::Create => Some(__gtf::<raw_ptr>(index, GTF_CREATE_WITNESS_AT_INDEX)),
}
}

Expand All @@ -326,20 +322,24 @@ pub fn tx_witness_pointer(index: u64) -> u64 {
///
/// # Returns
///
/// * [u64] - The length of the witness data at `index`.
/// * [Option<64>] - The length of the witness data at `index`.
///
/// # Examples
///
/// ```sway
/// use std::tx::tx_witness_data_length;
///
/// fn foo() {
/// let witness_data_length = tx_witness_data_length(0);
/// let witness_data_length = tx_witness_data_length(0).unwrap();
/// log(witness_data_length);
/// }
/// ```
pub fn tx_witness_data_length(index: u64) -> u64 {
__gtf::<u64>(index, GTF_WITNESS_DATA_LENGTH)
pub fn tx_witness_data_length(index: u64) -> Option<u64> {
if index >= tx_witnesses_count() {
return None
}

Some(__gtf::<u64>(index, GTF_WITNESS_DATA_LENGTH))
}

/// Get the witness data at `index`.
Expand All @@ -350,80 +350,73 @@ pub fn tx_witness_data_length(index: u64) -> u64 {
///
/// # Returns
///
/// * [T] - The witness data at `index`.
/// * [Option<T>] - The witness data at `index`.
///
/// # Examples
///
/// ```sway
/// use std::tx::tx_witness_data;
///
/// fn foo() {
/// let witness_data: u64 = tx_witness_data(0);
/// let witness_data: u64 = tx_witness_data(0).unwrap();
/// log(witness_data);
/// }
/// ```
pub fn tx_witness_data<T>(index: u64) -> T {
pub fn tx_witness_data<T>(index: u64) -> Option<T> {
if index >= tx_witnesses_count() {
return None
}

if __size_of::<T>() == 1 {
__gtf::<raw_ptr>(index, GTF_WITNESS_DATA).add::<u8>(7).read::<T>()
Some(__gtf::<raw_ptr>(index, GTF_WITNESS_DATA).add::<u8>(7).read::<T>())
} else {
__gtf::<raw_ptr>(index, GTF_WITNESS_DATA).read::<T>()
Some(__gtf::<raw_ptr>(index, GTF_WITNESS_DATA).read::<T>())
}
}

/// Get the transaction script start pointer.
///
/// # Returns
///
/// * [raw_ptr] - The transaction script start pointer.
///
/// # Reverts
///
/// * When the transaction type is of type `Transaction::Create`.
/// * [Option<raw_ptr>] - The transaction script start pointer.
///
/// # Examples
///
/// ```sway
/// use std::tx::tx_script_start_pointer;
///
/// fn foo() {
/// let script_start_pointer = tx_script_start_pointer();
/// let script_start_pointer = tx_script_start_pointer().unwrap();
/// log(script_start_pointer);
/// }
/// ```
pub fn tx_script_start_pointer() -> raw_ptr {
fn tx_script_start_pointer() -> Option<raw_ptr> {
match tx_type() {
Transaction::Script => __gtf::<raw_ptr>(0, GTF_SCRIPT_SCRIPT),
_ => revert(0),
Transaction::Script => Some(__gtf::<raw_ptr>(0, GTF_SCRIPT_SCRIPT)),
_ => None,
}
}

/// Get the transaction script data start pointer.
///
/// # Returns
///
/// * [raw_ptr] - The transaction script data start pointer.
///
/// # Reverts
///
/// * When the transaction type is of type `Transaction::Create`.
/// * [Option<raw_ptr>] - The transaction script data start pointer.
///
/// # Examples
///
/// ```sway
/// use std::tx::tx_script_data_start_pointer;
///
/// fn foo() {
/// let script_data_start_pointer = tx_script_data_start_pointer();
/// let script_data_start_pointer = tx_script_data_start_pointer().unwrap();
/// log(script_data_start_pointer);
/// }
/// ```
pub fn tx_script_data_start_pointer() -> raw_ptr {
fn tx_script_data_start_pointer() -> Option<raw_ptr> {
match tx_type() {
Transaction::Script => __gtf::<raw_ptr>(0, GTF_SCRIPT_SCRIPT_DATA),
_ => {
// transaction-create has no script data length
revert(0);
}
Transaction::Script => Some(__gtf::<raw_ptr>(0, GTF_SCRIPT_SCRIPT_DATA)),
_ => None,
}
}

Expand All @@ -436,11 +429,7 @@ pub fn tx_script_data_start_pointer() -> raw_ptr {
///
/// # Returns
///
/// * [T] - The script data, typed.
///
/// # Reverts
///
/// * When the transaction type is of type `Transaction::Create`.
/// * [Option<T>] - The script data, typed.
///
/// # Examples
///
Expand All @@ -452,10 +441,14 @@ pub fn tx_script_data_start_pointer() -> raw_ptr {
/// log(script_data);
/// }
/// ```
pub fn tx_script_data<T>() -> T {
pub fn tx_script_data<T>() -> Option<T> {
let ptr = tx_script_data_start_pointer();
if ptr.is_none() {
return None
}

// TODO some safety checks on the input data? We are going to assume it is the right type for now.
ptr.read::<T>()
Some(ptr.unwrap().read::<T>())
}

/// Get the script bytecode.
Expand All @@ -467,62 +460,59 @@ pub fn tx_script_data<T>() -> T {
///
/// # Returns
///
/// * [T] - The script bytecode.
///
/// # Reverts
///
/// * When the transaction type is of type `Transaction::Create`.
/// * [Option<T>] - The script bytecode.
///
/// # Examples
///
/// ```sway
/// use std::tx::tx_script_bytecode;
///
/// fn foo() {
/// let script_bytecode: [u64; 64] = tx_script_bytecode();
/// let script_bytecode: [u64; 64] = tx_script_bytecode().unwrap();
/// log(script_bytecode);
/// }
/// ```
pub fn tx_script_bytecode<T>() -> T {
tx_script_start_pointer().read::<T>()
pub fn tx_script_bytecode<T>() -> Option<T> {
match tx_type() {
Transaction::Script => Some(tx_script_start_pointer().unwrap().read::<T>()),
_ => None,
}
}

/// Get the hash of the script bytecode.
/// Reverts if not a transaction-script.
///
/// # Returns
///
/// * [b256] - The hash of the script bytecode.
///
/// # Reverts
///
/// * When the transaction type is of type `Transaction::Create`.
/// * [Option<b256>] - The hash of the script bytecode.
///
/// # Examples
///
/// ```sway
/// use std::tx::tx_script_bytecode_hash;
///
/// fn foo() {
/// let script_bytecode_hash: b256 = tx_script_bytecode_hash();
/// let script_bytecode_hash: b256 = tx_script_bytecode_hash().unwrap();
/// assert(script_bytecode_hash == 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef);
/// }
/// ```
pub fn tx_script_bytecode_hash() -> b256 {
pub fn tx_script_bytecode_hash() -> Option<b256> {
match tx_type() {
Transaction::Script => {
// Get the script memory details
let mut result_buffer = b256::zero();
let script_length = tx_script_length();
let script_ptr = tx_script_start_pointer();
let script_length = tx_script_length().unwrap();
let script_ptr = tx_script_start_pointer().unwrap();

// Run the hash opcode for the script in memory
asm(hash: result_buffer, ptr: script_ptr, len: script_length) {
s256 hash ptr len;
hash: b256
}
Some(
asm(hash: result_buffer, ptr: script_ptr, len: script_length) {
s256 hash ptr len;
hash: b256
},
)
},
_ => revert(0),
_ => None,
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::tx::*;

fn main() -> u64 {
assert(tx_witnesses_count() == 3);
assert(tx_witness_data::<u8>(1) == 1);
assert(tx_witness_data::<u64>(2) == 1234);
assert(tx_witness_data::<u8>(1).unwrap() == 1);
assert(tx_witness_data::<u64>(2).unwrap() == 1234);
0
}
Loading
Loading