Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
29d69ed
Add input version checks
MitchTurner May 19, 2025
6824392
Fix V1 test
MitchTurner May 19, 2025
1b3dc0d
Add checks on v2 inputs
MitchTurner May 19, 2025
ac94e87
Add tests for tx instead of just input
MitchTurner May 19, 2025
6213e0c
WIP add execution tests
MitchTurner May 19, 2025
6246e43
WIP add offsets and lookup of static witnesses and predicates in the …
MitchTurner May 21, 2025
5f5ef13
Get test passing... but idk why it needs the extra 8 bytes
MitchTurner May 22, 2025
fd4a8dc
Fix the way it finds the predicate data in the static witnesses
MitchTurner May 23, 2025
524e3c4
Cleanup, fix other tests
MitchTurner May 27, 2025
0cad75a
Add unhappy path test
MitchTurner May 28, 2025
3738c27
Hide more feature stuff, add CHANGELOG
MitchTurner May 28, 2025
b04f043
Add TODOs for the predicate data
MitchTurner May 28, 2025
8bbc93c
Appease Clippy-sama
MitchTurner May 28, 2025
2583262
Fix checks
MitchTurner May 28, 2025
306abce
Merge branch 'feature/v2-chargeable-tx' into feature/v2-chargeable-tx…
MitchTurner Jun 2, 2025
ddcee67
fix ts bindings
MitchTurner Jun 2, 2025
fb60beb
Quiet unused import warning
MitchTurner Jun 2, 2025
93d6498
Fix import
MitchTurner Jun 2, 2025
d33ecd2
Add missing conversions and variants
MitchTurner Jun 3, 2025
ae88eb5
Add missing feature flag
MitchTurner Jun 3, 2025
1bd11eb
Propogate feature flag change
MitchTurner Jun 3, 2025
0365c2b
Actually propogate flag changes
MitchTurner Jun 3, 2025
87eee3f
Replace `into` conversion that is needed with some features
MitchTurner Jun 12, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .changes/added/960.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add logic for handling coins in Script V2, including pointing at predicate code in the static witnesses
97 changes: 73 additions & 24 deletions fuel-tx/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ use crate::{
},
},
};
#[cfg(all(feature = "da-compression", feature = "chargeable-tx-v2"))]
use crate::{
BodyConstraints,
ChargeableTransaction,
field::ChargeableBody,
};
#[cfg(all(feature = "da-compression", feature = "chargeable-tx-v2"))]
use fuel_types::canonical::Serialize;

use crate::{
Cacheable,
Expand Down Expand Up @@ -173,6 +181,13 @@ impl TransactionBuilder<ScriptV2> {
};
Self::with_tx(tx)
}

pub fn add_static_witness(&mut self, witness: Witness) -> &mut Self {
if let Some(witnesses) = self.tx.static_witnesses_mut() {
witnesses.push(witness);
}
self
}
}

impl TransactionBuilder<Create> {
Expand Down Expand Up @@ -445,30 +460,6 @@ impl<Tx: Buildable> TransactionBuilder<Tx> {
self
}

pub fn add_unsigned_coin_input_v2(
&mut self,
secret: SecretKey,
utxo_id: crate::UtxoId,
amount: Word,
asset_id: fuel_types::AssetId,
tx_pointer: TxPointer,
) -> &mut Self {
let pk = secret.public_key();

let witness_index = self.upsert_secret(secret);

self.tx.add_unsigned_coin_input(
utxo_id,
&pk,
amount,
asset_id,
tx_pointer,
witness_index,
);

self
}

#[cfg(feature = "rand")]
pub fn add_random_fee_input(&mut self, rng: &mut StdRng) -> &mut Self {
self.add_unsigned_coin_input(
Expand Down Expand Up @@ -591,6 +582,64 @@ impl<Tx: Buildable> TransactionBuilder<Tx> {
}
}

#[cfg(all(feature = "da-compression", feature = "chargeable-tx-v2"))]
impl<B, M> TransactionBuilder<ChargeableTransaction<B, M>>
where
B: BodyConstraints,
ChargeableTransaction<B, M>: Buildable + ChargeableBody<B> + Serialize,
{
pub fn add_unsigned_coin_input_v2(
&mut self,
secret: SecretKey,
utxo_id: crate::UtxoId,
amount: Word,
asset_id: fuel_types::AssetId,
tx_pointer: TxPointer,
) -> &mut Self {
let pk = secret.public_key();

let witness_index = self.upsert_secret(secret);

self.tx.add_unsigned_coin_input_v2(
utxo_id,
&pk,
amount,
asset_id,
tx_pointer,
witness_index,
);

self
}
}

#[cfg(feature = "chargeable-tx-v2")]
impl TransactionBuilder<ScriptV2> {
pub fn add_unsigned_coin_input_v1(
&mut self,
secret: SecretKey,
utxo_id: crate::UtxoId,
amount: Word,
asset_id: fuel_types::AssetId,
tx_pointer: TxPointer,
) -> &mut Self {
let pk = secret.public_key();

let witness_index = self.upsert_secret(secret);

self.tx.add_unsigned_coin_input_v1(
utxo_id,
&pk,
amount,
asset_id,
tx_pointer,
witness_index,
);

self
}
}

impl<Tx: field::Outputs> TransactionBuilder<Tx> {
pub fn add_output(&mut self, output: Output) -> &mut Self {
self.tx.outputs_mut().push(output);
Expand Down
6 changes: 6 additions & 0 deletions fuel-tx/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
#![deny(unused_crate_dependencies)]
#![deny(unsafe_code)]

#[cfg(feature = "typescript")]
use serde_wasm_bindgen as _;

// TODO: Add docs

#[cfg(feature = "alloc")]
Expand Down Expand Up @@ -127,6 +130,9 @@ pub use transaction::{
policies,
};

#[cfg(feature = "chargeable-tx-v2")]
pub use transaction::ScriptV2;

#[cfg(feature = "da-compression")]
pub use transaction::{
BodyConstraints,
Expand Down
1 change: 1 addition & 0 deletions fuel-tx/src/test_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ mod use_std {
Input::MessageCoinPredicate(_) => (),
Input::MessageDataSigned(_) => (),
Input::MessageDataPredicate(_) => (),
#[cfg(feature = "chargeable-tx-v2")]
Input::InputV2(_) => {
todo!()
}
Expand Down
87 changes: 86 additions & 1 deletion fuel-tx/src/tests/valid_cases/input.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![allow(clippy::cast_possible_truncation)]
#![allow(non_snake_case)]

use super::PREDICATE_PARAMS;
use crate::{
ConsensusParameters,
builder::TransactionBuilder,
Expand Down Expand Up @@ -28,6 +28,9 @@ use rand::{
rngs::StdRng,
};

#[cfg(not(feature = "chargeable-tx-v2"))]
use tests::valid_cases::PREDICATE_PARAMS;

#[test]
fn input_coin_message_signature() {
fn test<Tx>(txs: &mut impl Iterator<Item = (Tx, Vec<SecretKey>)>)
Expand All @@ -45,6 +48,8 @@ fn input_coin_message_signature() {
let txhash = tx.id(&chain_id);
let outputs = tx.outputs();
let witnesses = tx.witnesses();
#[cfg(feature = "chargeable-tx-v2")]
let static_witnesses = tx.static_witnesses();

tx.inputs()
.iter()
Expand All @@ -57,6 +62,8 @@ fn input_coin_message_signature() {
&txhash,
outputs,
witnesses,
#[cfg(feature = "chargeable-tx-v2")]
static_witnesses,
&Default::default(),
&mut None,
),
Expand Down Expand Up @@ -207,6 +214,7 @@ fn duplicate_secrets_reuse_witness() {
)
}

#[cfg(not(feature = "chargeable-tx-v2"))]
#[test]
fn coin_predicate() {
let rng = &mut StdRng::seed_from_u64(8586);
Expand Down Expand Up @@ -268,7 +276,82 @@ fn coin_predicate() {

assert_eq!(ValidityError::InputPredicateOwner { index: 1 }, err);
}
#[cfg(feature = "chargeable-tx-v2")]
#[test]
fn coin_predicate_v2__check__correct_number_of_static_witnesses_passes() {
// given
let rng = &mut StdRng::seed_from_u64(8586);

let txhash: Bytes32 = rng.r#gen();

let predicate = generate_nonempty_padded_bytes(rng);
let owner = Input::predicate_owner(&predicate);
let static_witnesses = vec![Witness::default(); 2];
let predicate_index = 0;
let predicate_data_index = 1;

// when
let res = Input::coin_predicate_v2(
rng.r#gen(),
owner,
rng.r#gen(),
rng.r#gen(),
rng.r#gen(),
predicate_index,
predicate_data_index,
)
.check(
1,
&txhash,
&[],
&[],
&static_witnesses,
&Default::default(),
&mut None,
);

// then
assert!(res.is_ok(), "Expected check to pass");
}

#[cfg(feature = "chargeable-tx-v2")]
#[test]
fn coin_predicate_v2__check__incorrect_number_of_static_witnesses_fails() {
let rng = &mut StdRng::seed_from_u64(8586);

let txhash: Bytes32 = rng.r#gen();

let predicate = generate_nonempty_padded_bytes(rng);
let owner = Input::predicate_owner(&predicate);
let static_witnesses = vec![Witness::default(); 2];
let predicate_index = 2;
let predicate_data_index = 3;

let res = Input::coin_predicate_v2(
rng.r#gen(),
owner,
rng.r#gen(),
rng.r#gen(),
rng.r#gen(),
predicate_index,
predicate_data_index,
)
.check(
1,
&txhash,
&[],
&[],
&static_witnesses,
&Default::default(),
&mut None,
);

// then
let err = res.unwrap_err();
assert!(matches!(err, ValidityError::InputWitnessIndexBounds { .. }));
}

#[cfg(not(feature = "chargeable-tx-v2"))]
#[test]
fn contract() {
let rng = &mut StdRng::seed_from_u64(8586);
Expand Down Expand Up @@ -355,6 +438,7 @@ fn contract() {
);
}

#[cfg(not(feature = "chargeable-tx-v2"))]
#[test]
fn message_metadata() {
let rng = &mut StdRng::seed_from_u64(8586);
Expand Down Expand Up @@ -491,6 +575,7 @@ fn message_metadata() {
assert_eq!(ValidityError::InputPredicateDataLength { index: 1 }, err,);
}

#[cfg(not(feature = "chargeable-tx-v2"))]
#[test]
fn message_message_coin() {
let rng = &mut StdRng::seed_from_u64(8586);
Expand Down
Loading
Loading