From 767f4e6dea112715c3e12caa08962eec1e94b70a Mon Sep 17 00:00:00 2001 From: AurelienFT <32803821+AurelienFT@users.noreply.github.com> Date: Mon, 2 Dec 2024 23:38:16 +0100 Subject: [PATCH] Add expiration policy (#871) * Add expiration policy, some tests are still failing. * Fix tests * Update changelog * Update test and default expiration vlaue * Update fuel-tx/src/tests/bytes.rs Co-authored-by: Andrea Cerone <22031682+acerone85@users.noreply.github.com> * Add test and use helper function to policy exists. * Update fuel-tx/src/tests/valid_cases/transaction.rs Co-authored-by: Green Baneling * Update tests to follow the same pattern * add block height option to into_ready * Add tests success blob,upgrade,upload --------- Co-authored-by: Andrea Cerone <22031682+acerone85@users.noreply.github.com> Co-authored-by: Green Baneling --- CHANGELOG.md | 1 + fuel-asm/src/args.rs | 4 + fuel-tx/src/builder.rs | 7 ++ fuel-tx/src/tests/bytes.rs | 16 ++++ fuel-tx/src/tests/valid_cases/transaction.rs | 75 +++++++++++++++++++ .../src/tests/valid_cases/transaction/blob.rs | 33 ++++++++ .../tests/valid_cases/transaction/upgrade.rs | 35 +++++++++ .../tests/valid_cases/transaction/upload.rs | 34 +++++++++ fuel-tx/src/transaction.rs | 22 ++++++ fuel-tx/src/transaction/policies.rs | 36 ++++++++- .../transaction/types/input/snapshot_tests.rs | 7 ++ ...__tx_with_contract_snapshot_canonical.snap | 3 +- ...tests__tx_with_contract_snapshot_json.snap | 6 +- ...ith_predicate_coin_snapshot_canonical.snap | 3 +- ..._tx_with_predicate_coin_snapshot_json.snap | 6 +- ...with_predicate_message_coin_canonical.snap | 3 +- ...__tx_with_predicate_message_coin_json.snap | 6 +- ...with_predicate_message_data_canonical.snap | 3 +- ...__tx_with_predicate_message_data_json.snap | 6 +- ...x_with_signed_coin_snapshot_canonical.snap | 3 +- ...ts__tx_with_signed_coin_snapshot_json.snap | 6 +- ...tx_with_signed_message_coin_canonical.snap | 3 +- ...sts__tx_with_signed_message_coin_json.snap | 6 +- ...tx_with_signed_message_data_canonical.snap | 3 +- ...sts__tx_with_signed_message_data_json.snap | 6 +- fuel-tx/src/transaction/validity.rs | 9 ++- fuel-tx/src/transaction/validity/error.rs | 1 + fuel-vm/examples/single_step.rs | 1 + fuel-vm/src/checked_transaction.rs | 23 ++++-- fuel-vm/src/interpreter/debug.rs | 3 + .../instruction/tests/reserved_registers.rs | 2 +- .../src/interpreter/executors/main/tests.rs | 8 +- fuel-vm/src/interpreter/internal/tests.rs | 3 +- fuel-vm/src/interpreter/memory/tests.rs | 2 + fuel-vm/src/interpreter/metadata.rs | 4 + fuel-vm/src/tests/encoding.rs | 27 +++++++ fuel-vm/src/tests/gas_factor.rs | 2 +- fuel-vm/src/tests/metadata.rs | 9 +++ fuel-vm/src/tests/mod.rs | 1 + fuel-vm/src/tests/upgrade.rs | 8 +- fuel-vm/src/tests/upload.rs | 2 +- fuel-vm/src/tests/validation.rs | 68 +++++++++++++++++ fuel-vm/src/transactor.rs | 11 +-- 43 files changed, 468 insertions(+), 49 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf203a0cfe..1cdfebaac9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added +- [871](https://github.com/FuelLabs/fuel-vm/pull/871): Add `expiration` policy that prevent a transaction to be inserted after a given block height. - [870](https://github.com/FuelLabs/fuel-vm/pull/870): Add 3 new ZK-related opcodes: eadd (ecAdd on EVM), emul (ecMul on EVM), epar (ecPairing on EVM) - [875](https://github.com/FuelLabs/fuel-vm/pull/875): Updated `wasm-bindgen` to `0.2.97` diff --git a/fuel-asm/src/args.rs b/fuel-asm/src/args.rs index 1998bfd7dd..fb7e9d1620 100644 --- a/fuel-asm/src/args.rs +++ b/fuel-asm/src/args.rs @@ -245,6 +245,9 @@ crate::enum_try_from! { /// Set `$rA` to `tx.policies[count_ones(0b1111 & tx.policyTypes) - 1].maxFee` PolicyMaxFee = 0x504, + + /// Set `$rA` to `tx.policies[count_ones(0b11111 & tx.policyTypes) - 1].expiration` + PolicyExpiration = 0x505, }, Immediate12 } @@ -340,6 +343,7 @@ fn encode_gtf_args() { GTFArgs::PolicyTip, GTFArgs::PolicyWitnessLimit, GTFArgs::PolicyMaturity, + GTFArgs::PolicyExpiration, GTFArgs::PolicyMaxFee, ]; diff --git a/fuel-tx/src/builder.rs b/fuel-tx/src/builder.rs index f3d4145975..e5af5034a1 100644 --- a/fuel-tx/src/builder.rs +++ b/fuel-tx/src/builder.rs @@ -5,6 +5,7 @@ use crate::{ field::{ self, BytecodeWitnessIndex, + Expiration, Maturity, Tip, Witnesses, @@ -376,6 +377,12 @@ impl TransactionBuilder { self } + pub fn expiration(&mut self, expiration: BlockHeight) -> &mut Self { + self.tx.set_expiration(expiration); + + self + } + pub fn witness_limit(&mut self, witness_limit: Word) -> &mut Self { self.tx.set_witness_limit(witness_limit); diff --git a/fuel-tx/src/tests/bytes.rs b/fuel-tx/src/tests/bytes.rs index 3e60042c15..12ba7fb46c 100644 --- a/fuel-tx/src/tests/bytes.rs +++ b/fuel-tx/src/tests/bytes.rs @@ -382,6 +382,7 @@ fn transaction_serde_serialization_deserialization() { }, Policies::new() .with_tip(Word::MAX >> 1) + .with_expiration((u32::MAX >> 2).into()) .with_maturity((u32::MAX >> 3).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), @@ -397,6 +398,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -411,6 +413,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -425,6 +428,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -438,6 +442,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![i.clone()], @@ -451,6 +456,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -464,6 +470,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -477,6 +484,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -496,6 +504,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![i.clone()], @@ -513,6 +522,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -530,6 +540,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -547,6 +558,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -566,6 +578,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![i.clone()], @@ -583,6 +596,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -600,6 +614,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -617,6 +632,7 @@ fn transaction_serde_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], diff --git a/fuel-tx/src/tests/valid_cases/transaction.rs b/fuel-tx/src/tests/valid_cases/transaction.rs index c7059db6a6..f3c432dea3 100644 --- a/fuel-tx/src/tests/valid_cases/transaction.rs +++ b/fuel-tx/src/tests/valid_cases/transaction.rs @@ -123,6 +123,81 @@ fn maturity() { assert_eq!(ValidityError::TransactionMaturity, err); } +#[test] +fn script__check__valid_expiration_policy() { + let rng = &mut StdRng::seed_from_u64(8586); + + let block_height = 1000.into(); + + TransactionBuilder::script(generate_bytes(rng), generate_bytes(rng)) + // Given + .expiration(block_height) + .add_fee_input() + .finalize() + // When + .check(block_height, &test_params()) + // Then + .expect("Failed to validate script"); +} + +#[test] +fn script__check__invalid_expiration_policy() { + let rng = &mut StdRng::seed_from_u64(8586); + + // Given + let block_height = 1000.into(); + let old_block_height = 999u32.into(); + let err = TransactionBuilder::script(generate_bytes(rng), generate_bytes(rng)) + // Given + .expiration(old_block_height) + .add_fee_input() + .finalize() + // When + .check(block_height, &test_params()) + .expect_err("Expected erroneous transaction"); + + // Then + assert_eq!(ValidityError::TransactionExpiration, err); +} + +#[test] +fn create__check__valid_expiration_policy() { + let rng = &mut StdRng::seed_from_u64(8586); + + let block_height = 1000.into(); + + TransactionBuilder::create(rng.gen(), rng.gen(), vec![]) + // Given + .expiration(block_height) + .add_fee_input() + .add_contract_created() + .finalize() + // When + .check(block_height, &test_params()) + // Then + .expect("Failed to validate tx create"); +} + +#[test] +fn create__check__invalid_expiration_policy() { + let rng = &mut StdRng::seed_from_u64(8586); + + // Given + let block_height = 1000.into(); + let old_block_height = 999u32.into(); + let err = TransactionBuilder::create(rng.gen(), rng.gen(), vec![]) + .expiration(old_block_height) + .add_fee_input() + .add_contract_created() + .finalize() + // When + .check(block_height, &test_params()) + .expect_err("Failed to validate tx create"); + + // Then + assert_eq!(ValidityError::TransactionExpiration, err); +} + #[test] fn script__check__not_set_witness_limit_success() { // Given diff --git a/fuel-tx/src/tests/valid_cases/transaction/blob.rs b/fuel-tx/src/tests/valid_cases/transaction/blob.rs index d26d64ec4f..aff3d1b341 100644 --- a/fuel-tx/src/tests/valid_cases/transaction/blob.rs +++ b/fuel-tx/src/tests/valid_cases/transaction/blob.rs @@ -36,6 +36,7 @@ fn valid_blob_transaction() -> TransactionBuilder { predicate(), vec![], )); + builder.expiration(u32::MAX.into()); builder } @@ -69,6 +70,38 @@ fn check__fails_if_maturity_not_met() { assert_eq!(Err(ValidityError::TransactionMaturity), result); } +#[test] +fn check__success_if_expiration_met() { + // Given + let block_height: BlockHeight = 1000.into(); + let success_block_height = block_height.succ().unwrap(); + let tx = valid_blob_transaction() + .expiration(success_block_height) + .finalize_as_transaction(); + + // When + let result = tx.check(block_height, &test_params()); + + // Then + assert_eq!(Ok(()), result); +} + +#[test] +fn check__fails_if_expiration_not_met() { + // Given + let block_height: BlockHeight = 1000.into(); + let failing_block_height = block_height.pred().unwrap(); + let tx = valid_blob_transaction() + .expiration(failing_block_height) + .finalize_as_transaction(); + + // When + let result = tx.check(block_height, &test_params()); + + // Then + assert_eq!(Err(ValidityError::TransactionExpiration), result); +} + #[test] fn check__fails_if_blob_id_doesnt_match_payload() { // Given diff --git a/fuel-tx/src/tests/valid_cases/transaction/upgrade.rs b/fuel-tx/src/tests/valid_cases/transaction/upgrade.rs index 8ba4101552..d3661ad440 100644 --- a/fuel-tx/src/tests/valid_cases/transaction/upgrade.rs +++ b/fuel-tx/src/tests/valid_cases/transaction/upgrade.rs @@ -33,6 +33,7 @@ fn valid_upgrade_transaction() -> TransactionBuilder { vec![], )); builder.with_params(test_params()); + builder.expiration(u32::MAX.into()); builder } @@ -52,6 +53,7 @@ fn valid_upgrade_transaction_with_message() -> TransactionBuilder { vec![], )); builder.with_params(test_params()); + builder.expiration(u32::MAX.into()); builder } @@ -91,6 +93,39 @@ fn maturity() { assert_eq!(Err(ValidityError::TransactionMaturity), result); } +#[test] +fn upgrade__check__success_if_expiration_met() { + // Given + let block_height: BlockHeight = 1000.into(); + let success_block_height = block_height.succ().unwrap(); + let tx = valid_upgrade_transaction() + .expiration(success_block_height) + .finalize_as_transaction(); + + // When + let result = tx.check(block_height, &test_params()); + + // Then + assert_eq!(Ok(()), result); +} + +#[test] +fn upgrade__check__valid_expiration_policy() { + let block_height: BlockHeight = 1000.into(); + let failing_block_height = block_height.pred().unwrap(); + + // Given + let tx = valid_upgrade_transaction() + .expiration(failing_block_height) + .finalize_as_transaction(); + + // When + let result = tx.check(block_height, &test_params()); + + // Then + assert_eq!(Err(ValidityError::TransactionExpiration), result); +} + #[test] fn check__not_set_witness_limit_success() { // Given diff --git a/fuel-tx/src/tests/valid_cases/transaction/upload.rs b/fuel-tx/src/tests/valid_cases/transaction/upload.rs index 4f4c6c6de0..a449b60e76 100644 --- a/fuel-tx/src/tests/valid_cases/transaction/upload.rs +++ b/fuel-tx/src/tests/valid_cases/transaction/upload.rs @@ -52,6 +52,7 @@ fn valid_upload_transaction() -> TransactionBuilder { predicate(), vec![], )); + builder.expiration(u32::MAX.into()); builder } @@ -168,6 +169,39 @@ fn maturity() { assert_eq!(Err(ValidityError::TransactionMaturity), result); } +#[test] +fn upload__check__success_if_expiration_met() { + // Given + let block_height: BlockHeight = 1000.into(); + let success_block_height = block_height.succ().unwrap(); + let tx = valid_upload_transaction() + .expiration(success_block_height) + .finalize_as_transaction(); + + // When + let result = tx.check(block_height, &test_params()); + + // Then + assert_eq!(Ok(()), result); +} + +#[test] +fn upload__check__valid_expiration_policy() { + let block_height: BlockHeight = 1000.into(); + let failing_block_height = block_height.pred().unwrap(); + + // Given + let tx = valid_upload_transaction() + .expiration(failing_block_height) + .finalize_as_transaction(); + + // When + let result = tx.check(block_height, &test_params()); + + // Then + assert_eq!(Err(ValidityError::TransactionExpiration), result); +} + #[test] fn check__not_set_witness_limit_success() { // Given diff --git a/fuel-tx/src/transaction.rs b/fuel-tx/src/transaction.rs index dd3fc9524e..69f67817a5 100644 --- a/fuel-tx/src/transaction.rs +++ b/fuel-tx/src/transaction.rs @@ -832,6 +832,28 @@ pub mod field { } } + pub trait Expiration { + fn expiration(&self) -> BlockHeight; + fn set_expiration(&mut self, value: BlockHeight); + } + + impl Expiration for T { + #[inline(always)] + fn expiration(&self) -> BlockHeight { + self.policies() + .get(PolicyType::Expiration) + .and_then(|value| u32::try_from(value).ok()) + .unwrap_or(u32::MAX) + .into() + } + + #[inline(always)] + fn set_expiration(&mut self, block_height: BlockHeight) { + self.policies_mut() + .set(PolicyType::Expiration, Some(*block_height.deref() as u64)) + } + } + pub trait MaxFeeLimit { fn max_fee_limit(&self) -> Word; fn set_max_fee_limit(&mut self, value: Word); diff --git a/fuel-tx/src/transaction/policies.rs b/fuel-tx/src/transaction/policies.rs index abd5cb8a7e..54f0821f9d 100644 --- a/fuel-tx/src/transaction/policies.rs +++ b/fuel-tx/src/transaction/policies.rs @@ -33,6 +33,8 @@ bitflags::bitflags! { const Maturity = 1 << 2; /// If set, the max fee is present in the policies. const MaxFee = 1 << 3; + /// If set, the expiration is present in the policies. + const Expiration = 1 << 4; } } @@ -80,6 +82,7 @@ pub enum PolicyType { WitnessLimit, Maturity, MaxFee, + Expiration, } impl PolicyType { @@ -89,6 +92,7 @@ impl PolicyType { PolicyType::WitnessLimit => 1, PolicyType::Maturity => 2, PolicyType::MaxFee => 3, + PolicyType::Expiration => 4, } } @@ -98,6 +102,7 @@ impl PolicyType { PolicyType::WitnessLimit => PoliciesBits::WitnessLimit, PolicyType::Maturity => PoliciesBits::Maturity, PolicyType::MaxFee => PoliciesBits::MaxFee, + PolicyType::Expiration => PoliciesBits::Expiration, } } } @@ -163,6 +168,12 @@ impl Policies { self } + /// Sets the `expiration` policy. + pub fn with_expiration(mut self, expiration: BlockHeight) -> Self { + self.set(PolicyType::Expiration, Some(*expiration.deref() as u64)); + self + } + /// Sets the `max_fee` policy. pub fn with_max_fee(mut self, max_fee: Word) -> Self { self.set(PolicyType::MaxFee, Some(max_fee)); @@ -217,6 +228,12 @@ impl Policies { } } + if let Some(expiration) = self.get(PolicyType::Expiration) { + if expiration > u32::MAX as u64 { + return false; + } + } + true } @@ -284,6 +301,12 @@ impl Deserialize for Policies { } } + if let Some(expiration) = self.get(PolicyType::Expiration) { + if expiration > u32::MAX as u64 { + return Err(Error::Unknown("The expiration in more than `u32::MAX`")); + } + } + Ok(()) } } @@ -300,11 +323,16 @@ impl Distribution for Standard { values: Policies::values_for_bitmask(bits, values), }; - if policies.get(PolicyType::Maturity).is_some() { + if policies.is_set(PolicyType::Maturity) { let maturity: u32 = rng.gen(); policies.set(PolicyType::Maturity, Some(maturity as u64)); } + if policies.is_set(PolicyType::Expiration) { + let expiration: u32 = rng.gen(); + policies.set(PolicyType::Expiration, Some(expiration as u64)); + } + policies } } @@ -355,7 +383,8 @@ pub mod typescript { #[test] fn values_for_bitmask_produces_expected_values() { const MAX_BITMASK: u32 = 1 << POLICIES_NUMBER; - const VALUES: [Word; POLICIES_NUMBER] = [0x1000001, 0x2000001, 0x3000001, 0x4000001]; + const VALUES: [Word; POLICIES_NUMBER] = + [0x1000001, 0x2000001, 0x3000001, 0x4000001, 0x5000001]; // Given let mut set = hashbrown::HashSet::new(); @@ -374,7 +403,8 @@ fn values_for_bitmask_produces_expected_values() { #[test] fn canonical_serialization_deserialization_for_any_combination_of_values_works() { const MAX_BITMASK: u32 = 1 << POLICIES_NUMBER; - const VALUES: [Word; POLICIES_NUMBER] = [0x1000001, 0x2000001, 0x3000001, 0x4000001]; + const VALUES: [Word; POLICIES_NUMBER] = + [0x1000001, 0x2000001, 0x3000001, 0x4000001, 0x5000001]; for bitmask in 0..MAX_BITMASK { let bits = diff --git a/fuel-tx/src/transaction/types/input/snapshot_tests.rs b/fuel-tx/src/transaction/types/input/snapshot_tests.rs index a2f767bb97..55a98c1eaf 100644 --- a/fuel-tx/src/transaction/types/input/snapshot_tests.rs +++ b/fuel-tx/src/transaction/types/input/snapshot_tests.rs @@ -22,6 +22,7 @@ fn tx_with_signed_coin_snapshot() -> Transaction { })) .tip(1) .maturity(123.into()) + .expiration(456.into()) .max_fee_limit(1000000) .witness_limit(1000) .finalize_as_transaction() @@ -59,6 +60,7 @@ fn tx_with_predicate_coin_snapshot() -> Transaction { })) .tip(1) .maturity(123.into()) + .expiration(456.into()) .max_fee_limit(1000000) .finalize_as_transaction() } @@ -91,6 +93,7 @@ fn tx_with_contract_snapshot() -> Transaction { })) .tip(1) .maturity(123.into()) + .expiration(456.into()) .max_fee_limit(1000000) .finalize_as_transaction() } @@ -127,6 +130,7 @@ fn tx_with_signed_message_coin() -> Transaction { })) .tip(1) .maturity(123.into()) + .expiration(456.into()) .max_fee_limit(1000000) .witness_limit(1000) .finalize_as_transaction() @@ -164,6 +168,7 @@ fn tx_with_predicate_message_coin() -> Transaction { })) .tip(1) .maturity(123.into()) + .expiration(456.into()) .max_fee_limit(1000000) .finalize_as_transaction() } @@ -199,6 +204,7 @@ fn tx_with_signed_message_data() -> Transaction { })) .tip(1) .maturity(123.into()) + .expiration(456.into()) .max_fee_limit(1000000) .witness_limit(1000) .finalize_as_transaction() @@ -236,6 +242,7 @@ fn tx_with_predicate_message_data() -> Transaction { })) .tip(1) .maturity(123.into()) + .expiration(456.into()) .max_fee_limit(1000000) .finalize_as_transaction() } diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_contract_snapshot_canonical.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_contract_snapshot_canonical.snap index 34679e26d6..88ee7542c8 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_contract_snapshot_canonical.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_contract_snapshot_canonical.snap @@ -1,5 +1,6 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: hex +snapshot_kind: text --- -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d0000000000000001000000000000000000000000000000000000000000000001000000000000007b00000000000f424000000000000000010101010101010101010101010101010101010101010101010101010101010101000000000000000202020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303000000000000002e00000000000000050505050505050505050505050505050505050505050505050505050505050505 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d0000000000000001000000000000000000000000000000000000000000000001000000000000007b00000000000f424000000000000001c800000000000000010101010101010101010101010101010101010101010101010101010101010101000000000000000202020202020202020202020202020202020202020202020202020202020202020303030303030303030303030303030303030303030303030303030303030303000000000000002e00000000000000050505050505050505050505050505050505050505050505050505050505050505 diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_contract_snapshot_json.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_contract_snapshot_json.snap index e444d623db..65d89202c1 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_contract_snapshot_json.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_contract_snapshot_json.snap @@ -1,6 +1,7 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: json +snapshot_kind: text --- { "Script": { @@ -11,12 +12,13 @@ expression: json "script_data": [] }, "policies": { - "bits": "Tip | Maturity | MaxFee", + "bits": "Tip | Maturity | MaxFee | Expiration", "values": [ 1, 0, 123, - 1000000 + 1000000, + 456 ] }, "inputs": [ diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_coin_snapshot_canonical.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_coin_snapshot_canonical.snap index 6f6ce42451..67ee8bdff9 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_coin_snapshot_canonical.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_coin_snapshot_canonical.snap @@ -1,5 +1,6 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: hex +snapshot_kind: text --- -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d0000000000000001000000000000000000000000000000000000000000000001000000000000007b00000000000f42400000000000000000010101010101010101010101010101010101010101010101010101010101010100000000000000020202020202020202020202020202020202020202020202020202020202020202000000000000000b0505050505050505050505050505050505050505050505050505050505050505000000000000002e0000000000000005000000000000000000000000000186a0000000000000000a000000000000000c0303030303030303030300000000000004040404040404040404040400000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d0000000000000001000000000000000000000000000000000000000000000001000000000000007b00000000000f424000000000000001c80000000000000000010101010101010101010101010101010101010101010101010101010101010100000000000000020202020202020202020202020202020202020202020202020202020202020202000000000000000b0505050505050505050505050505050505050505050505050505050505050505000000000000002e0000000000000005000000000000000000000000000186a0000000000000000a000000000000000c0303030303030303030300000000000004040404040404040404040400000000 diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_coin_snapshot_json.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_coin_snapshot_json.snap index 5a2b799e5d..bab4afdc57 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_coin_snapshot_json.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_coin_snapshot_json.snap @@ -1,6 +1,7 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: json +snapshot_kind: text --- { "Script": { @@ -11,12 +12,13 @@ expression: json "script_data": [] }, "policies": { - "bits": "Tip | Maturity | MaxFee", + "bits": "Tip | Maturity | MaxFee | Expiration", "values": [ 1, 0, 123, - 1000000 + 1000000, + 456 ] }, "inputs": [ diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_coin_canonical.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_coin_canonical.snap index bf42f441c5..50d6071ce6 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_coin_canonical.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_coin_canonical.snap @@ -1,5 +1,6 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: hex +snapshot_kind: text --- -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d0000000000000001000000000000000000000000000000000000000000000001000000000000007b00000000000f424000000000000000020202020202020202020202020202020202020202020202020202020202020202030303030303030303030303030303030303030303030303030303030303030300000000000000040505050505050505050505050505050505050505050505050505050505050505000000000000000000000000000186a00000000000000000000000000000000b000000000000000c0707070707070707070707000000000008080808080808080808080800000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d0000000000000001000000000000000000000000000000000000000000000001000000000000007b00000000000f424000000000000001c800000000000000020202020202020202020202020202020202020202020202020202020202020202030303030303030303030303030303030303030303030303030303030303030300000000000000040505050505050505050505050505050505050505050505050505050505050505000000000000000000000000000186a00000000000000000000000000000000b000000000000000c0707070707070707070707000000000008080808080808080808080800000000 diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_coin_json.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_coin_json.snap index a2561a716f..b468746f27 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_coin_json.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_coin_json.snap @@ -1,6 +1,7 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: json +snapshot_kind: text --- { "Script": { @@ -11,12 +12,13 @@ expression: json "script_data": [] }, "policies": { - "bits": "Tip | Maturity | MaxFee", + "bits": "Tip | Maturity | MaxFee | Expiration", "values": [ 1, 0, 123, - 1000000 + 1000000, + 456 ] }, "inputs": [ diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_data_canonical.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_data_canonical.snap index 9b21b56acb..5be68958d1 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_data_canonical.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_data_canonical.snap @@ -1,5 +1,6 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: hex +snapshot_kind: text --- -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000d0000000000000001000000000000000000000000000000000000000000000001000000000000007b00000000000f424000000000000000020202020202020202020202020202020202020202020202020202020202020202030303030303030303030303030303030303030303030303030303030303030300000000000000040505050505050505050505050505050505050505050505050505050505050505000000000000000000000000000186a0000000000000000a000000000000000b000000000000000c060606060606060606060000000000000707070707070707070707000000000008080808080808080808080800000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001d0000000000000001000000000000000000000000000000000000000000000001000000000000007b00000000000f424000000000000001c800000000000000020202020202020202020202020202020202020202020202020202020202020202030303030303030303030303030303030303030303030303030303030303030300000000000000040505050505050505050505050505050505050505050505050505050505050505000000000000000000000000000186a0000000000000000a000000000000000b000000000000000c060606060606060606060000000000000707070707070707070707000000000008080808080808080808080800000000 diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_data_json.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_data_json.snap index 16b6f028cd..ecc605d18c 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_data_json.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_predicate_message_data_json.snap @@ -1,6 +1,7 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: json +snapshot_kind: text --- { "Script": { @@ -11,12 +12,13 @@ expression: json "script_data": [] }, "policies": { - "bits": "Tip | Maturity | MaxFee", + "bits": "Tip | Maturity | MaxFee | Expiration", "values": [ 1, 0, 123, - 1000000 + 1000000, + 456 ] }, "inputs": [ diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_coin_snapshot_canonical.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_coin_snapshot_canonical.snap index 4c5b48f81e..b9e1ad50eb 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_coin_snapshot_canonical.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_coin_snapshot_canonical.snap @@ -1,5 +1,6 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: hex +snapshot_kind: text --- -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000100000000000000000000000000000000000000000000000100000000000003e8000000000000007b00000000000f42400000000000000000010101010101010101010101010101010101010101010101010101010101010100000000000000020202020202020202020202020202020202020202020202020202020202020202000000000000000b0505050505050505050505050505050505050505050505050505050505050505000000000000002e00000000000000050000000000000004000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f000000000000000100000000000000000000000000000000000000000000000100000000000003e8000000000000007b00000000000f424000000000000001c80000000000000000010101010101010101010101010101010101010101010101010101010101010100000000000000020202020202020202020202020202020202020202020202020202020202020202000000000000000b0505050505050505050505050505050505050505050505050505050505050505000000000000002e00000000000000050000000000000004000000000000000000000000000000000000000000000000 diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_coin_snapshot_json.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_coin_snapshot_json.snap index 5df010573e..e3768856c7 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_coin_snapshot_json.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_coin_snapshot_json.snap @@ -1,6 +1,7 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: json +snapshot_kind: text --- { "Script": { @@ -11,12 +12,13 @@ expression: json "script_data": [] }, "policies": { - "bits": "Tip | WitnessLimit | Maturity | MaxFee", + "bits": "Tip | WitnessLimit | Maturity | MaxFee | Expiration", "values": [ 1, 1000, 123, - 1000000 + 1000000, + 456 ] }, "inputs": [ diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_coin_canonical.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_coin_canonical.snap index a7c67135e2..398416e4c9 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_coin_canonical.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_coin_canonical.snap @@ -1,5 +1,6 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: hex +snapshot_kind: text --- -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000100000000000000000000000000000000000000000000000100000000000003e8000000000000007b00000000000f42400000000000000002020202020202020202020202020202020202020202020202020202020202020203030303030303030303030303030303030303030303030303030303030303030000000000000004050505050505050505050505050505050505050505050505050505050505050500000000000000060000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f000000000000000100000000000000000000000000000000000000000000000100000000000003e8000000000000007b00000000000f424000000000000001c80000000000000002020202020202020202020202020202020202020202020202020202020202020203030303030303030303030303030303030303030303030303030303030303030000000000000004050505050505050505050505050505050505050505050505050505050505050500000000000000060000000000000000000000000000000000000000000000000000000000000000 diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_coin_json.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_coin_json.snap index 5fa7392c65..0455339e4f 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_coin_json.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_coin_json.snap @@ -1,6 +1,7 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: json +snapshot_kind: text --- { "Script": { @@ -11,12 +12,13 @@ expression: json "script_data": [] }, "policies": { - "bits": "Tip | WitnessLimit | Maturity | MaxFee", + "bits": "Tip | WitnessLimit | Maturity | MaxFee | Expiration", "values": [ 1, 1000, 123, - 1000000 + 1000000, + 456 ] }, "inputs": [ diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_data_canonical.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_data_canonical.snap index 5ca3af76bc..8512452261 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_data_canonical.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_data_canonical.snap @@ -1,5 +1,6 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: hex +snapshot_kind: text --- -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000f000000000000000100000000000000000000000000000000000000000000000100000000000003e8000000000000007b00000000000f42400000000000000002020202020202020202020202020202020202020202020202020202020202020203030303030303030303030303030303030303030303030303030303030303030000000000000004050505050505050505050505050505050505050505050505050505050505050500000000000000060000000000000000000000000000000a0000000000000000000000000000000007070707070707070707000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f000000000000000100000000000000000000000000000000000000000000000100000000000003e8000000000000007b00000000000f424000000000000001c80000000000000002020202020202020202020202020202020202020202020202020202020202020203030303030303030303030303030303030303030303030303030303030303030000000000000004050505050505050505050505050505050505050505050505050505050505050500000000000000060000000000000000000000000000000a0000000000000000000000000000000007070707070707070707000000000000 diff --git a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_data_json.snap b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_data_json.snap index 513a250b20..054d06599c 100644 --- a/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_data_json.snap +++ b/fuel-tx/src/transaction/types/input/snapshots/fuel_tx__transaction__types__input__snapshot_tests__tx_with_signed_message_data_json.snap @@ -1,6 +1,7 @@ --- source: fuel-tx/src/transaction/types/input/snapshot_tests.rs expression: json +snapshot_kind: text --- { "Script": { @@ -11,12 +12,13 @@ expression: json "script_data": [] }, "policies": { - "bits": "Tip | WitnessLimit | Maturity | MaxFee", + "bits": "Tip | WitnessLimit | Maturity | MaxFee | Expiration", "values": [ 1, 1000, 123, - 1000000 + 1000000, + 456 ] }, "inputs": [ diff --git a/fuel-tx/src/transaction/validity.rs b/fuel-tx/src/transaction/validity.rs index a28ee7ee35..d03a180833 100644 --- a/fuel-tx/src/transaction/validity.rs +++ b/fuel-tx/src/transaction/validity.rs @@ -1,5 +1,8 @@ use crate::{ - field::Maturity, + field::{ + Expiration, + Maturity, + }, input::{ coin::{ CoinPredicate, @@ -358,6 +361,10 @@ where Err(ValidityError::TransactionMaturity)?; } + if tx.expiration() < block_height { + Err(ValidityError::TransactionExpiration)?; + } + if tx.inputs().len() > tx_params.max_inputs() as usize { Err(ValidityError::TransactionInputsMax)? } diff --git a/fuel-tx/src/transaction/validity/error.rs b/fuel-tx/src/transaction/validity/error.rs index a61891d872..bf50484f20 100644 --- a/fuel-tx/src/transaction/validity/error.rs +++ b/fuel-tx/src/transaction/validity/error.rs @@ -128,6 +128,7 @@ pub enum ValidityError { TransactionPoliciesAreInvalid, TransactionNoGasPricePolicy, TransactionMaturity, + TransactionExpiration, TransactionMaxFeeNotSet, TransactionInputsMax, TransactionOutputsMax, diff --git a/fuel-vm/examples/single_step.rs b/fuel-vm/examples/single_step.rs index 852cde2167..c2843b1774 100644 --- a/fuel-vm/examples/single_step.rs +++ b/fuel-vm/examples/single_step.rs @@ -56,6 +56,7 @@ fn main() { 0, consensus_params.gas_costs(), consensus_params.fee_params(), + None, ) .expect("Failed to finalize tx"); diff --git a/fuel-vm/src/checked_transaction.rs b/fuel-vm/src/checked_transaction.rs index a4ddd6b92a..c4b228c840 100644 --- a/fuel-vm/src/checked_transaction.rs +++ b/fuel-vm/src/checked_transaction.rs @@ -8,6 +8,7 @@ #![allow(non_upper_case_globals)] use fuel_tx::{ + field::Expiration, Create, Mint, Script, @@ -188,6 +189,7 @@ impl Checked { gas_price: Word, gas_costs: &GasCosts, fee_parameters: &FeeParameters, + block_height: Option, ) -> Result, CheckError> { let Checked { transaction, @@ -205,6 +207,12 @@ impl Checked { let max_fee_from_policies = transaction.max_fee_limit(); let max_fee_from_gas_price = fee.max_fee(); + if let Some(block_height) = block_height { + if block_height > transaction.expiration() { + return Err(CheckError::Validity(ValidityError::TransactionExpiration)); + } + } + if max_fee_from_gas_price > max_fee_from_policies { Err(CheckError::InsufficientMaxFee { max_fee_from_policies, @@ -1682,7 +1690,7 @@ mod tests { .clone() .into_checked(Default::default(), ¶ms) .unwrap() - .into_ready(gas_price, &GasCosts::default(), params.fee_params()) + .into_ready(gas_price, &GasCosts::default(), params.fee_params(), None) .expect("`new_transaction` should be fully valid"); // given @@ -1694,7 +1702,7 @@ mod tests { // when let err = bigger_checked - .into_ready(gas_price, &GasCosts::default(), params.fee_params()) + .into_ready(gas_price, &GasCosts::default(), params.fee_params(), None) .expect_err("Expected invalid transaction"); let max_fee_from_policies = match err { @@ -1759,7 +1767,7 @@ mod tests { let err = transaction .into_checked(Default::default(), &consensus_params) .unwrap() - .into_ready(max_gas_price, &gas_costs, fee_params) + .into_ready(max_gas_price, &gas_costs, fee_params, None) .expect_err("overflow expected"); assert_eq!(err, CheckError::Validity(ValidityError::BalanceOverflow)); @@ -1786,7 +1794,7 @@ mod tests { let err = transaction .into_checked(Default::default(), &consensus_params) .unwrap() - .into_ready(gas_price, &gas_costs, fee_params) + .into_ready(gas_price, &gas_costs, fee_params, None) .expect_err("overflow expected"); // then @@ -1812,7 +1820,7 @@ mod tests { .clone() .into_checked(block_height, ¶ms) .unwrap() - .into_ready(gas_price, &gas_costs, params.fee_params()) + .into_ready(gas_price, &gas_costs, params.fee_params(), None) .expect("Should be valid"); // given @@ -1827,7 +1835,7 @@ mod tests { tx_without_enough_to_pay_for_tip .into_checked(block_height, ¶ms) .unwrap() - .into_ready(gas_price, &gas_costs, params.fee_params()) + .into_ready(gas_price, &gas_costs, params.fee_params(), None) .expect_err("Expected invalid transaction"); // when @@ -1845,7 +1853,7 @@ mod tests { tx.clone() .into_checked(block_height, ¶ms) .unwrap() - .into_ready(gas_price, &GasCosts::default(), params.fee_params()) + .into_ready(gas_price, &GasCosts::default(), params.fee_params(), None) .expect("Should be valid"); } @@ -1868,6 +1876,7 @@ mod tests { gas_price, &GasCosts::default(), consensus_params.fee_params(), + None, ) .expect_err("overflow expected"); diff --git a/fuel-vm/src/interpreter/debug.rs b/fuel-vm/src/interpreter/debug.rs index 354337873f..b39b2152c9 100644 --- a/fuel-vm/src/interpreter/debug.rs +++ b/fuel-vm/src/interpreter/debug.rs @@ -102,6 +102,7 @@ mod tests { gas_price, consensus_params.gas_costs(), consensus_params.fee_params(), + None, ) .unwrap(); @@ -181,6 +182,7 @@ mod tests { gas_price, consensus_params.gas_costs(), consensus_params.fee_params(), + None, ) .unwrap(); @@ -234,6 +236,7 @@ mod tests { gas_price, consensus_params.gas_costs(), consensus_params.fee_params(), + None, ) .unwrap(); diff --git a/fuel-vm/src/interpreter/executors/instruction/tests/reserved_registers.rs b/fuel-vm/src/interpreter/executors/instruction/tests/reserved_registers.rs index 8b76445750..ad60ff4559 100644 --- a/fuel-vm/src/interpreter/executors/instruction/tests/reserved_registers.rs +++ b/fuel-vm/src/interpreter/executors/instruction/tests/reserved_registers.rs @@ -75,7 +75,7 @@ fn cant_write_to_reserved_registers(raw_random_instruction: u32) -> TestResult { let tx = tx .into_checked(block_height, &consensus_params) .expect("failed to check tx") - .into_ready(zero_gas_price, vm.gas_costs(), &fee_params) + .into_ready(zero_gas_price, vm.gas_costs(), &fee_params, None) .expect("failed dynamic checks"); vm.init_script(tx).expect("Failed to init VM"); diff --git a/fuel-vm/src/interpreter/executors/main/tests.rs b/fuel-vm/src/interpreter/executors/main/tests.rs index 47608882a4..4d1d4d194d 100644 --- a/fuel-vm/src/interpreter/executors/main/tests.rs +++ b/fuel-vm/src/interpreter/executors/main/tests.rs @@ -137,7 +137,7 @@ fn transact__tx_with_wrong_gas_price_causes_error() { // When let tx = valid_script_tx() - .into_ready(tx_gas_price, &Default::default(), &Default::default()) + .into_ready(tx_gas_price, &Default::default(), &Default::default(), None) .unwrap(); let err = interpreter.transact(tx).unwrap_err(); @@ -172,7 +172,7 @@ fn deploy__tx_with_wrong_gas_price_causes_error() { // When let tx = valid_create_tx() - .into_ready(tx_gas_price, &Default::default(), &Default::default()) + .into_ready(tx_gas_price, &Default::default(), &Default::default(), None) .unwrap(); let err = interpreter.deploy(tx).unwrap_err(); @@ -213,7 +213,7 @@ fn upgrade__tx_with_wrong_gas_price_causes_error() { // When let tx = valid_upgrade_tx() - .into_ready(tx_gas_price, &Default::default(), &Default::default()) + .into_ready(tx_gas_price, &Default::default(), &Default::default(), None) .unwrap(); let err = interpreter.upgrade(tx).unwrap_err(); @@ -254,7 +254,7 @@ fn upload__tx_with_wrong_gas_price_causes_error() { // When let tx = valid_upload_tx() - .into_ready(tx_gas_price, &Default::default(), &Default::default()) + .into_ready(tx_gas_price, &Default::default(), &Default::default(), None) .unwrap(); let err = interpreter.upload(tx).unwrap_err(); diff --git a/fuel-vm/src/interpreter/internal/tests.rs b/fuel-vm/src/interpreter/internal/tests.rs index cac62b7b40..6919c263f4 100644 --- a/fuel-vm/src/interpreter/internal/tests.rs +++ b/fuel-vm/src/interpreter/internal/tests.rs @@ -60,7 +60,7 @@ fn external_balance() { .script_gas_limit(100) .maturity(maturity) .finalize_checked(height) - .into_ready(gas_price, &gas_costs, &fee_params) + .into_ready(gas_price, &gas_costs, &fee_params, None) .unwrap(); vm.init_script(tx).expect("Failed to init VM!"); @@ -140,6 +140,7 @@ fn variable_output_updates_in_memory() { zero_gas_price, &GasCosts::default(), consensus_params.fee_params(), + None, ) .unwrap(); diff --git a/fuel-vm/src/interpreter/memory/tests.rs b/fuel-vm/src/interpreter/memory/tests.rs index 65931efe06..e92cf59cf6 100644 --- a/fuel-vm/src/interpreter/memory/tests.rs +++ b/fuel-vm/src/interpreter/memory/tests.rs @@ -38,6 +38,7 @@ fn memcopy() { zero_gas_price, consensus_params.gas_costs(), consensus_params.fee_params(), + None, ) .unwrap(); @@ -105,6 +106,7 @@ fn stack_alloc_ownership() { gas_price, consensus_params.gas_costs(), consensus_params.fee_params(), + None, ) .unwrap(); vm.init_script(tx).expect("Failed to init VM"); diff --git a/fuel-vm/src/interpreter/metadata.rs b/fuel-vm/src/interpreter/metadata.rs index 9a9955c213..bc2062f297 100644 --- a/fuel-vm/src/interpreter/metadata.rs +++ b/fuel-vm/src/interpreter/metadata.rs @@ -185,6 +185,10 @@ impl GTFInput<'_, Tx> { .policies() .get(PolicyType::Maturity) .ok_or(PanicReason::PolicyIsNotSet)?, + GTFArgs::PolicyExpiration => tx + .policies() + .get(PolicyType::Expiration) + .ok_or(PanicReason::PolicyIsNotSet)?, GTFArgs::PolicyMaxFee => tx .policies() .get(PolicyType::MaxFee) diff --git a/fuel-vm/src/tests/encoding.rs b/fuel-vm/src/tests/encoding.rs index 5772f44ec1..ddbb0be34a 100644 --- a/fuel-vm/src/tests/encoding.rs +++ b/fuel-vm/src/tests/encoding.rs @@ -232,6 +232,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![i.clone()], @@ -245,6 +246,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![i.clone()], @@ -258,6 +260,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![i.clone()], @@ -271,6 +274,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![i.clone()], @@ -284,6 +288,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -297,6 +302,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -310,6 +316,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -343,6 +350,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), [0xdd; 32].into(), @@ -356,6 +364,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), [0xdd; 32].into(), @@ -369,6 +378,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), [0xdd; 32].into(), @@ -382,6 +392,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), [0xdd; 32].into(), @@ -420,6 +431,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![i.clone()], @@ -434,6 +446,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -448,6 +461,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -462,6 +476,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -475,6 +490,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![i.clone()], @@ -488,6 +504,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -501,6 +518,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -514,6 +532,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -533,6 +552,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![i.clone()], @@ -550,6 +570,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -567,6 +588,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -584,6 +606,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -600,6 +623,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![i.clone()], @@ -614,6 +638,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -628,6 +653,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], @@ -642,6 +668,7 @@ fn transaction_canonical_serialization_deserialization() { Policies::new() .with_tip(Word::MAX >> 1) .with_maturity((u32::MAX >> 3).into()) + .with_expiration((u32::MAX >> 2).into()) .with_witness_limit(Word::MAX >> 4) .with_max_fee(Word::MAX >> 5), vec![], diff --git a/fuel-vm/src/tests/gas_factor.rs b/fuel-vm/src/tests/gas_factor.rs index 07f51bc77d..530b610014 100644 --- a/fuel-vm/src/tests/gas_factor.rs +++ b/fuel-vm/src/tests/gas_factor.rs @@ -44,7 +44,7 @@ fn gas_factor_rounds_correctly() { .coin_input(AssetId::default(), input) .change_output(AssetId::default()) .build() - .into_ready(gas_price, &gas_costs, &fee_params) + .into_ready(gas_price, &gas_costs, &fee_params, None) .unwrap(); let profiler = GasProfiler::default(); diff --git a/fuel-vm/src/tests/metadata.rs b/fuel-vm/src/tests/metadata.rs index 6a713b8d60..0658ccd655 100644 --- a/fuel-vm/src/tests/metadata.rs +++ b/fuel-vm/src/tests/metadata.rs @@ -369,6 +369,7 @@ fn get_transaction_fields() { let gas_limit = 10_000_000; let maturity = 50.into(); let height = 122.into(); + let expiration = 123.into(); let input = 10_000_000; let tx_params = TxParameters::default(); @@ -441,6 +442,7 @@ fn get_transaction_fields() { let tx = TransactionBuilder::script(vec![], vec![]) .maturity(maturity) + .expiration(expiration) .with_gas_costs(gas_costs) .script_gas_limit(gas_limit) .add_unsigned_coin_input( @@ -602,6 +604,12 @@ fn get_transaction_fields() { op::eq(0x10, 0x10, 0x11), op::and(0x20, 0x20, 0x10), + op::movi(0x19, 0x00), + op::movi(0x11, *expiration as Immediate18), + op::gtf_args(0x10, 0x19, GTFArgs::PolicyExpiration), + op::eq(0x10, 0x10, 0x11), + op::and(0x20, 0x20, 0x10), + op::movi(0x19, 0x00), op::movi(0x11, max_fee_limit as Immediate18), op::gtf_args(0x10, 0x19, GTFArgs::PolicyMaxFee), @@ -943,6 +951,7 @@ fn get_transaction_fields() { let tx = builder .tip(tip) .maturity(maturity) + .expiration(expiration) .script_gas_limit(gas_limit) .witness_limit(witness_limit) .max_fee_limit(max_fee_limit) diff --git a/fuel-vm/src/tests/mod.rs b/fuel-vm/src/tests/mod.rs index 319af6d792..59a667ee92 100644 --- a/fuel-vm/src/tests/mod.rs +++ b/fuel-vm/src/tests/mod.rs @@ -1,4 +1,5 @@ #![allow(clippy::arithmetic_side_effects, clippy::cast_possible_truncation)] +#![allow(non_snake_case)] use futures as _; use ntest as _; diff --git a/fuel-vm/src/tests/upgrade.rs b/fuel-vm/src/tests/upgrade.rs index 812cdb46e7..089daf5a28 100644 --- a/fuel-vm/src/tests/upgrade.rs +++ b/fuel-vm/src/tests/upgrade.rs @@ -124,7 +124,7 @@ mod state_transition { let gas_price = 0; client.set_gas_price(gas_price); let tx = valid_transaction(state_transition_hash) - .into_ready(gas_price, &GasCosts::default(), &Default::default()) + .into_ready(gas_price, &GasCosts::default(), &Default::default(), None) .expect("failed to generate ready tx"); // When @@ -154,7 +154,7 @@ mod state_transition { let gas_price = 1; client.set_gas_price(gas_price); let tx = valid_transaction(state_transition_hash) - .into_ready(gas_price, &GasCosts::default(), &Default::default()) + .into_ready(gas_price, &GasCosts::default(), &Default::default(), None) .expect("failed to generate ready tx"); // When @@ -341,7 +341,7 @@ mod consensus_parameters { let gas_price = 0; client.set_gas_price(gas_price); let tx = valid_transaction() - .into_ready(gas_price, &GasCosts::default(), &Default::default()) + .into_ready(gas_price, &GasCosts::default(), &Default::default(), None) .expect("failed to generate ready tx"); // When @@ -370,7 +370,7 @@ mod consensus_parameters { let gas_price = 1; client.set_gas_price(gas_price); let tx = valid_transaction() - .into_ready(gas_price, &GasCosts::default(), &Default::default()) + .into_ready(gas_price, &GasCosts::default(), &Default::default(), None) .expect("failed to generate ready tx"); // When diff --git a/fuel-vm/src/tests/upload.rs b/fuel-vm/src/tests/upload.rs index 796d64e276..c3622c974e 100644 --- a/fuel-vm/src/tests/upload.rs +++ b/fuel-vm/src/tests/upload.rs @@ -357,7 +357,7 @@ fn transact__with_non_zero_gas_price_affects_change_output() { ) .into_checked_basic(Default::default(), &Default::default()) .expect("Failed to generate checked tx") - .into_ready(gas_price, &GasCosts::default(), &Default::default()) + .into_ready(gas_price, &GasCosts::default(), &Default::default(), None) .expect("Failed to generate ready tx"); // When diff --git a/fuel-vm/src/tests/validation.rs b/fuel-vm/src/tests/validation.rs index 5eed6c1e10..92f19043d9 100644 --- a/fuel-vm/src/tests/validation.rs +++ b/fuel-vm/src/tests/validation.rs @@ -67,6 +67,74 @@ fn transaction_can_be_executed_after_maturity() { assert!(result.is_ok()); } +#[test] +fn transaction__execution__works_before_expiration() { + let arb_max_fee = 1; + + let rng = &mut StdRng::seed_from_u64(2322u64); + + // Given + const EXPIRATION: BlockHeight = BlockHeight::new(2); + const BLOCK_HEIGHT: BlockHeight = BlockHeight::new(1); + let tx = TransactionBuilder::script( + Some(op::ret(1)).into_iter().collect(), + Default::default(), + ) + .max_fee_limit(arb_max_fee) + .add_unsigned_coin_input( + SecretKey::random(rng), + rng.gen(), + arb_max_fee, + Default::default(), + rng.gen(), + ) + .script_gas_limit(100) + .expiration(EXPIRATION) + .finalize_checked(BLOCK_HEIGHT); + + // When + let result = TestBuilder::new(2322u64) + .block_height(BLOCK_HEIGHT) + .execute_tx(tx); + + // Then + assert!(result.is_ok()); +} + +#[test] +fn transaction__execution__works_current_height_expiration() { + let arb_max_fee = 1; + + let rng = &mut StdRng::seed_from_u64(2322u64); + + // Given + const EXPIRATION: BlockHeight = BlockHeight::new(1); + const BLOCK_HEIGHT: BlockHeight = BlockHeight::new(1); + let tx = TransactionBuilder::script( + Some(op::ret(1)).into_iter().collect(), + Default::default(), + ) + .max_fee_limit(arb_max_fee) + .add_unsigned_coin_input( + SecretKey::random(rng), + rng.gen(), + arb_max_fee, + Default::default(), + rng.gen(), + ) + .script_gas_limit(100) + .expiration(EXPIRATION) + .finalize_checked(BLOCK_HEIGHT); + + // When + let result = TestBuilder::new(2322u64) + .block_height(BLOCK_HEIGHT) + .execute_tx(tx); + + // Then + assert!(result.is_ok()); +} + /// Malleable fields should not affect validity of the create transaction #[test] fn malleable_fields_do_not_affect_validity_of_create() { diff --git a/fuel-vm/src/transactor.rs b/fuel-vm/src/transactor.rs index 8cb06564ed..2f52aa5ee4 100644 --- a/fuel-vm/src/transactor.rs +++ b/fuel-vm/src/transactor.rs @@ -214,7 +214,7 @@ where let fee_params = self.interpreter.fee_params(); let ready = checked - .into_ready(gas_price, gas_costs, fee_params) + .into_ready(gas_price, gas_costs, fee_params, None) .map_err(InterpreterError::CheckError)?; self.deploy_ready_tx(ready) @@ -238,7 +238,7 @@ where let fee_params = self.interpreter.fee_params(); let ready = checked - .into_ready(gas_price, gas_costs, fee_params) + .into_ready(gas_price, gas_costs, fee_params, None) .map_err(InterpreterError::CheckError)?; self.execute_ready_upgrade_tx(ready) @@ -262,7 +262,7 @@ where let fee_params = self.interpreter.fee_params(); let ready = checked - .into_ready(gas_price, gas_costs, fee_params) + .into_ready(gas_price, gas_costs, fee_params, None) .map_err(InterpreterError::CheckError)?; self.execute_ready_upload_tx(ready) @@ -286,7 +286,7 @@ where let fee_params = self.interpreter.fee_params(); let ready = checked - .into_ready(gas_price, gas_costs, fee_params) + .into_ready(gas_price, gas_costs, fee_params, None) .map_err(InterpreterError::CheckError)?; self.execute_ready_blob_tx(ready) @@ -314,9 +314,10 @@ where let gas_price = self.interpreter.gas_price(); let gas_costs = self.interpreter.gas_costs(); let fee_params = self.interpreter.fee_params(); + let block_height = self.interpreter.context().block_height(); match tx - .into_ready(gas_price, gas_costs, fee_params) + .into_ready(gas_price, gas_costs, fee_params, block_height) .map_err(InterpreterError::CheckError) { Ok(ready_tx) => self.transact_ready_tx(ready_tx),