Skip to content

Commit

Permalink
Add support for Transaction::Upload, Transaction::Upgrade, and `T…
Browse files Browse the repository at this point in the history
…ransaction::Blob` (#6500)

## Description

The current `Transaction` enum in the `tx` library does not support the
new transaction types in the Fuel Specs:
https://docs.fuel.network/docs/nightly/specs/tx-format/transaction/

## Changes

- Adds support for `Transaction::Upload`, `Transaction::Upgrade`, and
`Transaction::Blob`.
- Implements `Eq` for `Transaction`
- Adds missing GTF opcodes. These will be implemented in another PR.
- Adds additional warnings in inline documentation

## Notes

- Required for mainnet
- `tx_witness_data()` returns an `Option<T>` and thus does not support
ownership types. This will be updated to `Bytes` in the future

## 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>
Co-authored-by: Sophie Dankel <47993817+sdankel@users.noreply.github.com>
Co-authored-by: IGI-111 <igi-111@protonmail.com>
  • Loading branch information
4 people authored Sep 11, 2024
1 parent 439f935 commit d76a146
Show file tree
Hide file tree
Showing 19 changed files with 808 additions and 28 deletions.
20 changes: 16 additions & 4 deletions sway-lib-std/src/inputs.sw
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ use ::tx::{
tx_type,
};
use core::ops::Eq;

const GTF_INPUT_TYPE = 0x200;
use ::revert::revert;

// GTF Opcode const selectors
//
pub const GTF_INPUT_TYPE = 0x200;
// pub const GTF_INPUT_COIN_TX_ID = 0x201;
// pub const GTF_INPUT_COIN_OUTPUT_INDEX = 0x202;
pub const GTF_INPUT_COIN_OWNER = 0x203;
Expand All @@ -33,7 +32,7 @@ pub const GTF_INPUT_COIN_PREDICATE_LENGTH = 0x209;
pub const GTF_INPUT_COIN_PREDICATE_DATA_LENGTH = 0x20A;
pub const GTF_INPUT_COIN_PREDICATE = 0x20B;
pub const GTF_INPUT_COIN_PREDICATE_DATA = 0x20C;

// pub const GTF_INPUT_COIN_PREDICATE_GAS_USED = 0x20D;
// pub const GTF_INPUT_CONTRACT_CONTRACT_ID = 0x225;
pub const GTF_INPUT_MESSAGE_SENDER = 0x240;
pub const GTF_INPUT_MESSAGE_RECIPIENT = 0x241;
Expand All @@ -46,6 +45,7 @@ pub const GTF_INPUT_MESSAGE_PREDICATE_DATA_LENGTH = 0x247;
pub const GTF_INPUT_MESSAGE_DATA = 0x248;
pub const GTF_INPUT_MESSAGE_PREDICATE = 0x249;
pub const GTF_INPUT_MESSAGE_PREDICATE_DATA = 0x24A;
// pub const GTF_INPUT_MESSAGE_PREDICATE_GAS_USED = 0x24B;

/// The input type for a transaction.
pub enum Input {
Expand Down Expand Up @@ -113,6 +113,10 @@ pub fn input_type(index: u64) -> Option<Input> {
///
/// * [u16] - The number of inputs in the transaction.
///
/// # Reverts
///
/// * When the input type is unrecognized. This should never happen.
///
/// # Examples
///
/// ```sway
Expand All @@ -127,6 +131,10 @@ pub fn input_count() -> u16 {
match tx_type() {
Transaction::Script => __gtf::<u16>(0, GTF_SCRIPT_INPUTS_COUNT),
Transaction::Create => __gtf::<u16>(0, GTF_CREATE_INPUTS_COUNT),
Transaction::Upgrade => __gtf::<u16>(0, GTF_SCRIPT_INPUTS_COUNT),
Transaction::Upload => __gtf::<u16>(0, GTF_SCRIPT_INPUTS_COUNT),
Transaction::Blob => __gtf::<u16>(0, GTF_SCRIPT_INPUTS_COUNT),
_ => revert(0),
}
}

Expand Down Expand Up @@ -158,6 +166,10 @@ fn input_pointer(index: u64) -> Option<raw_ptr> {
match tx_type() {
Transaction::Script => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_INPUT_AT_INDEX)),
Transaction::Create => Some(__gtf::<raw_ptr>(index, GTF_CREATE_INPUT_AT_INDEX)),
Transaction::Upgrade => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_INPUT_AT_INDEX)),
Transaction::Upload => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_INPUT_AT_INDEX)),
Transaction::Blob => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_INPUT_AT_INDEX)),
_ => None,
}
}

Expand Down
8 changes: 8 additions & 0 deletions sway-lib-std/src/outputs.sw
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ fn output_pointer(index: u64) -> Option<raw_ptr> {
match tx_type() {
Transaction::Script => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_OUTPUT_AT_INDEX)),
Transaction::Create => Some(__gtf::<raw_ptr>(index, GTF_CREATE_OUTPUT_AT_INDEX)),
Transaction::Upgrade => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_OUTPUT_AT_INDEX)),
Transaction::Upload => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_OUTPUT_AT_INDEX)),
Transaction::Blob => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_OUTPUT_AT_INDEX)),
_ => None,
}
}

Expand Down Expand Up @@ -139,6 +143,10 @@ pub fn output_count() -> u16 {
match tx_type() {
Transaction::Script => __gtf::<u16>(0, GTF_SCRIPT_OUTPUTS_COUNT),
Transaction::Create => __gtf::<u16>(0, GTF_CREATE_OUTPUTS_COUNT),
Transaction::Upgrade => __gtf::<u16>(0, GTF_SCRIPT_OUTPUTS_COUNT),
Transaction::Upload => __gtf::<u16>(0, GTF_SCRIPT_OUTPUTS_COUNT),
Transaction::Blob => __gtf::<u16>(0, GTF_SCRIPT_OUTPUTS_COUNT),
_ => revert(0),
}
}

Expand Down
92 changes: 83 additions & 9 deletions sway-lib-std/src/tx.sw
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ library;

use ::revert::revert;
use ::option::Option::{self, *};
use ::alloc::alloc_bytes;

// GTF Opcode const selectors
//
Expand All @@ -18,6 +19,7 @@ pub const GTF_SCRIPT_SCRIPT_DATA = 0x00A;
pub const GTF_SCRIPT_INPUT_AT_INDEX = 0x00B;
pub const GTF_SCRIPT_OUTPUT_AT_INDEX = 0x00C;
pub const GTF_SCRIPT_WITNESS_AT_INDEX = 0x00D;

pub const GTF_TX_LENGTH = 0x00E;

// pub const GTF_CREATE_BYTECODE_WITNESS_INDEX = 0x101;
Expand Down Expand Up @@ -46,10 +48,35 @@ pub enum Transaction {
Script: (),
/// A contract deployment transaction.
Create: (),
/// The transaction is created by the block producer and is not signed.
///
/// # Additional Information
///
/// NOTE: This should never be valid in execution but it provided for congruency to the FuelVM specs.
Mint: (),
/// The Upgrade transaction allows upgrading either consensus parameters or state transition function used by the network to produce future blocks.
Upgrade: (),
///The Upload transaction allows the huge bytecode to be divided into subsections and uploaded slowly to the chain.
Upload: (),
/// The Blob inserts a simple binary blob in the chain. It's raw immutable data that can be cheaply loaded by the VM and used as instructions or just data.
Blob: (),
}

impl core::ops::Eq for Transaction {
fn eq(self, other: Self) -> bool {
match (self, other) {
(Transaction::Script, Transaction::Script) => true,
(Transaction::Create, Transaction::Create) => true,
(Transaction::Mint, Transaction::Mint) => true,
(Transaction::Upgrade, Transaction::Upgrade) => true,
(Transaction::Upload, Transaction::Upload) => true,
(Transaction::Blob, Transaction::Blob) => true,
_ => false,
}
}
}

/// Get the type of the current transaction.
/// Either `Transaction::Script` or `Transaction::Create`.
///
/// # Returns
///
Expand All @@ -73,13 +100,28 @@ pub enum Transaction {
/// Transaction::Create => {
/// log("Contract deployment transaction");
/// },
/// Transaction::Mint => {
/// log("This should never happen");
/// },
/// Transaction::Upgrade => {
/// log("Upgrade transaction");
/// },
/// Transaction::Upload => {
/// log("Upload transaction");
/// },
/// Transaction::Blob => {
/// log("Blob transaction");
/// },
/// }
/// }
/// ```
pub fn tx_type() -> Transaction {
match __gtf::<u8>(0, GTF_TYPE) {
0u8 => Transaction::Script,
1u8 => Transaction::Create,
3u8 => Transaction::Upgrade,
4u8 => Transaction::Upload,
5u8 => Transaction::Blob,
_ => revert(0),
}
}
Expand Down Expand Up @@ -233,7 +275,7 @@ pub fn tx_max_fee() -> Option<u64> {
pub fn tx_script_length() -> Option<u64> {
match tx_type() {
Transaction::Script => Some(__gtf::<u64>(0, GTF_SCRIPT_SCRIPT_LENGTH)),
Transaction::Create => None,
_ => None,
}
}

Expand All @@ -256,7 +298,7 @@ pub fn tx_script_length() -> Option<u64> {
pub fn tx_script_data_length() -> Option<u64> {
match tx_type() {
Transaction::Script => Some(__gtf::<u64>(0, GTF_SCRIPT_SCRIPT_DATA_LENGTH)),
Transaction::Create => None,
_ => None,
}
}

Expand All @@ -266,6 +308,10 @@ pub fn tx_script_data_length() -> Option<u64> {
///
/// * [u64] - The witnesses count for the transaction.
///
/// # Reverts
///
/// * When the transaction type is unrecognized. This should never happen.
///
/// # Examples
///
/// ```sway
Expand All @@ -280,6 +326,10 @@ pub fn tx_witnesses_count() -> u64 {
match tx_type() {
Transaction::Script => __gtf::<u64>(0, GTF_SCRIPT_WITNESSES_COUNT),
Transaction::Create => __gtf::<u64>(0, GTF_CREATE_WITNESSES_COUNT),
Transaction::Upgrade => __gtf::<u64>(0, GTF_SCRIPT_WITNESSES_COUNT),
Transaction::Upload => __gtf::<u64>(0, GTF_SCRIPT_WITNESSES_COUNT),
Transaction::Blob => __gtf::<u64>(0, GTF_SCRIPT_WITNESSES_COUNT),
_ => revert(0),
}
}

Expand Down Expand Up @@ -311,6 +361,10 @@ fn tx_witness_pointer(index: u64) -> Option<raw_ptr> {
match tx_type() {
Transaction::Script => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_WITNESS_AT_INDEX)),
Transaction::Create => Some(__gtf::<raw_ptr>(index, GTF_CREATE_WITNESS_AT_INDEX)),
Transaction::Upgrade => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_WITNESS_AT_INDEX)),
Transaction::Upload => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_WITNESS_AT_INDEX)),
Transaction::Blob => Some(__gtf::<raw_ptr>(index, GTF_SCRIPT_WITNESS_AT_INDEX)),
_ => None,
}
}

Expand Down Expand Up @@ -344,6 +398,11 @@ pub fn tx_witness_data_length(index: u64) -> Option<u64> {

/// Get the witness data at `index`.
///
/// # Additional Information
///
/// **Unsafe. Assumes the type is correct.**
/// This function does not support ownership types(Vec, Bytes, String, etc).
///
/// # Arguments
///
/// * `index` - The index of the witness to get the data for.
Expand All @@ -367,10 +426,26 @@ pub fn tx_witness_data<T>(index: u64) -> Option<T> {
return None
}

if __size_of::<T>() == 1 {
Some(__gtf::<raw_ptr>(index, GTF_WITNESS_DATA).add::<u8>(7).read::<T>())
let length = match tx_witness_data_length(index) {
Some(len) => len,
None => return None,
};

if __is_reference_type::<T>() {
let witness_data_ptr = __gtf::<raw_ptr>(index, GTF_WITNESS_DATA);
let new_ptr = alloc_bytes(length);
witness_data_ptr.copy_bytes_to(new_ptr, length);

Some(asm(ptr: new_ptr) {
ptr: T
})
} else {
Some(__gtf::<raw_ptr>(index, GTF_WITNESS_DATA).read::<T>())
// u8 is the only value type that is less than 8 bytes and should be handled separately
if __size_of::<T>() == 1 {
Some(__gtf::<raw_ptr>(index, GTF_WITNESS_DATA).add::<u8>(7).read::<T>())
} else {
Some(__gtf::<raw_ptr>(index, GTF_WITNESS_DATA).read::<T>())
}
}
}

Expand Down Expand Up @@ -424,8 +499,8 @@ fn tx_script_data_start_pointer() -> Option<raw_ptr> {
///
/// # Additional Information
///
/// **Unsafe.**
/// **Assumes the type is correct.**
/// **Unsafe. Assumes the type is correct.**
/// This function does not support ownership types(Vec, Bytes, String, etc).
///
/// # Returns
///
Expand Down Expand Up @@ -480,7 +555,6 @@ pub fn tx_script_bytecode<T>() -> Option<T> {
}

/// Get the hash of the script bytecode.
/// Reverts if not a transaction-script.
///
/// # Returns
///
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use test_fuel_coin_abi::*;
#[cfg(experimental_new_encoding = false)]
const FUEL_COIN_CONTRACT_ID = 0xec2277ebe007ade87e3d797c3b1e070dcd542d5ef8f038b471f262ef9cebc87c;
#[cfg(experimental_new_encoding = true)]
const FUEL_COIN_CONTRACT_ID = 0xf8c7b4d09f9964ab4c437ac7f5cbd6dbad7e1f218fce452c5807aac3c67afa6f;
const FUEL_COIN_CONTRACT_ID = 0xf2fecff29038dab2ef571397ea5507359265c9154608e7de36ccbea20ed5c8aa;

#[cfg(experimental_new_encoding = false)]
const BALANCE_CONTRACT_ID = 0xf6cd545152ac83225e8e7df2efb5c6fa6e37bc9b9e977b5ea8103d28668925df;
Expand Down
1 change: 1 addition & 0 deletions test/src/in_language_tests/Forc.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ members = [
"test_programs/revert_inline_tests",
"test_programs/storage_key_inline_tests",
"test_programs/string_inline_tests",
"test_programs/tx_inline_tests",
"test_programs/u128_inline_tests",
"test_programs/vec_inline_tests",
"test_programs/array_conversions_b256_inline_tests",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[project]
authors = ["Fuel Labs <contact@fuel.sh>"]
entry = "main.sw"
license = "Apache-2.0"
name = "tx_inline_tests"

[dependencies]
std = { path = "../../../../../sway-lib-std" }
Loading

0 comments on commit d76a146

Please sign in to comment.