Skip to content

Commit

Permalink
Add a feature that propose u32 tx_pointer in fuel-tx and fuel-vm
Browse files Browse the repository at this point in the history
  • Loading branch information
AurelienFT committed Jan 20, 2025
1 parent 3c93830 commit e4f0651
Show file tree
Hide file tree
Showing 5 changed files with 112 additions and 5 deletions.
1 change: 1 addition & 0 deletions fuel-tx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ random = ["fuel-crypto/random", "fuel-types/random", "rand"]
std = ["alloc", "fuel-asm/std", "fuel-crypto/std", "fuel-merkle/std", "fuel-types/std", "itertools/default", "rand?/default", "serde/default", "hex/std"]
alloc = ["hashbrown", "fuel-types/alloc", "itertools/use_alloc", "fuel-merkle", "strum", "strum_macros", "bitflags", "postcard", "educe", "derive_more", "fuel-asm/serde", "fuel-types/serde"]
da-compression = ["fuel-compression"]
u32-tx-pointer = []

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] }
3 changes: 2 additions & 1 deletion fuel-tx/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,8 @@ impl TransactionBuilder<Blob> {
impl TransactionBuilder<Mint> {
pub fn mint(
block_height: BlockHeight,
tx_index: u16,
#[cfg(feature = "u32-tx-pointer")] tx_index: u32,
#[cfg(not(feature = "u32-tx-pointer"))] tx_index: u16,
input_contract: input::contract::Contract,
output_contract: output::contract::Contract,
mint_amount: Word,
Expand Down
81 changes: 80 additions & 1 deletion fuel-tx/src/tx_pointer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,20 @@ pub struct TxPointer {
/// Block height
block_height: BlockHeight,
/// Transaction index
#[cfg(feature = "u32-tx-pointer")]
tx_index: u32,
#[cfg(not(feature = "u32-tx-pointer"))]
tx_index: u16,
}

impl TxPointer {
pub const LEN: usize = 2 * WORD_SIZE;

pub const fn new(block_height: BlockHeight, tx_index: u16) -> Self {
pub const fn new(
block_height: BlockHeight,
#[cfg(feature = "u32-tx-pointer")] tx_index: u32,
#[cfg(not(feature = "u32-tx-pointer"))] tx_index: u16,
) -> Self {
Self {
block_height,
tx_index,
Expand All @@ -52,6 +59,12 @@ impl TxPointer {
self.block_height
}

#[cfg(feature = "u32-tx-pointer")]
pub const fn tx_index(&self) -> u32 {
self.tx_index
}

#[cfg(not(feature = "u32-tx-pointer"))]
pub const fn tx_index(&self) -> u16 {
self.tx_index
}
Expand All @@ -70,12 +83,28 @@ impl fmt::Display for TxPointer {
}
}

#[cfg(feature = "u32-tx-pointer")]
impl fmt::LowerHex for TxPointer {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:08x}{:08x}", self.block_height, self.tx_index)
}
}

#[cfg(not(feature = "u32-tx-pointer"))]
impl fmt::LowerHex for TxPointer {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:08x}{:04x}", self.block_height, self.tx_index)
}
}

#[cfg(feature = "u32-tx-pointer")]
impl fmt::UpperHex for TxPointer {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:08X}{:08X}", self.block_height, self.tx_index)
}
}

#[cfg(not(feature = "u32-tx-pointer"))]
impl fmt::UpperHex for TxPointer {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:08X}{:04X}", self.block_height, self.tx_index)
Expand All @@ -85,6 +114,26 @@ impl fmt::UpperHex for TxPointer {
impl str::FromStr for TxPointer {
type Err = &'static str;

#[cfg(feature = "u32-tx-pointer")]
/// TxPointer is encoded as 16 hex characters:
/// - 8 characters for block height
/// - 8 characters for tx index
fn from_str(s: &str) -> Result<Self, Self::Err> {
const ERR: &str = "Invalid encoded byte in TxPointer";

if s.len() != 16 || !s.is_char_boundary(8) {
return Err(ERR)
}

let (block_height, tx_index) = s.split_at(8);

let block_height = u32::from_str_radix(block_height, 16).map_err(|_| ERR)?;
let tx_index = u32::from_str_radix(tx_index, 16).map_err(|_| ERR)?;

Ok(Self::new(block_height.into(), tx_index))
}

#[cfg(not(feature = "u32-tx-pointer"))]
/// TxPointer is encoded as 12 hex characters:
/// - 8 characters for block height
/// - 4 characters for tx index
Expand Down Expand Up @@ -144,6 +193,7 @@ pub mod typescript {
}
}

#[cfg(not(feature = "u32-tx-pointer"))]
#[test]
fn fmt_encode_decode() {
use core::str::FromStr;
Expand Down Expand Up @@ -172,6 +222,35 @@ fn fmt_encode_decode() {
}
}

#[cfg(feature = "u32-tx-pointer")]
#[test]
fn fmt_encode_decode_u32() {
use core::str::FromStr;

let cases = vec![(83473, 3829)];

for (block_height, tx_index) in cases {
let tx_pointer = TxPointer::new(block_height.into(), tx_index);

let lower = format!("{tx_pointer:x}");
let upper = format!("{tx_pointer:X}");

assert_eq!(lower, format!("{block_height:08x}{tx_index:08x}"));
assert_eq!(upper, format!("{block_height:08X}{tx_index:08X}"));

let x = TxPointer::from_str(&lower).expect("failed to decode from str");
assert_eq!(tx_pointer, x);

let x = TxPointer::from_str(&upper).expect("failed to decode from str");
assert_eq!(tx_pointer, x);

let bytes = tx_pointer.clone().to_bytes();
let tx_pointer_p = TxPointer::from_bytes(&bytes).expect("failed to deserialize");

assert_eq!(tx_pointer, tx_pointer_p);
}
}

/// See https://github.com/FuelLabs/fuel-vm/issues/521
#[test]
fn decode_bug() {
Expand Down
1 change: 1 addition & 0 deletions fuel-vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ test-helpers = [
"tai64",
"fuel-crypto/test-helpers",
]
u32-tx-pointer = ["fuel-tx/u32-tx-pointer"]

[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(fuzzing)'] }
31 changes: 28 additions & 3 deletions fuel-vm/src/tests/validation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,16 @@ fn malleable_fields_do_not_affect_validity_of_create() {
match tx.inputs_mut()[0] {
Input::CoinPredicate(CoinPredicate {
ref mut tx_pointer, ..
}) => *tx_pointer = TxPointer::from_str("123456780001").unwrap(),
}) => {
#[cfg(not(feature = "u32-tx-pointer"))]
{
*tx_pointer = TxPointer::from_str("123456780001").unwrap()
}
#[cfg(feature = "u32-tx-pointer")]
{
*tx_pointer = TxPointer::from_str("1234567800000001").unwrap()
}
}
_ => unreachable!(),
};

Expand Down Expand Up @@ -318,7 +327,16 @@ fn malleable_fields_do_not_affect_validity_of_script() {
match tx.inputs_mut()[0] {
Input::CoinPredicate(CoinPredicate {
ref mut tx_pointer, ..
}) => *tx_pointer = TxPointer::from_str("123456780001").unwrap(),
}) => {
#[cfg(not(feature = "u32-tx-pointer"))]
{
*tx_pointer = TxPointer::from_str("123456780001").unwrap()
}
#[cfg(feature = "u32-tx-pointer")]
{
*tx_pointer = TxPointer::from_str("1234567800000001").unwrap()
}
}
_ => unreachable!(),
};

Expand All @@ -333,7 +351,14 @@ fn malleable_fields_do_not_affect_validity_of_script() {
*utxo_id = UtxoId::new([1; 32].into(), 0);
*balance_root = [2; 32].into();
*state_root = [3; 32].into();
*tx_pointer = TxPointer::from_str("123456780001").unwrap();
#[cfg(not(feature = "u32-tx-pointer"))]
{
*tx_pointer = TxPointer::from_str("123456780001").unwrap();
}
#[cfg(feature = "u32-tx-pointer")]
{
*tx_pointer = TxPointer::from_str("1234567800000001").unwrap();
}
}
_ => unreachable!(),
};
Expand Down

0 comments on commit e4f0651

Please sign in to comment.