diff --git a/CHANGELOG.md b/CHANGELOG.md index a74e3dd969..78548b5e1b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - [#653](https://github.com/FuelLabs/fuel-vm/pull/653): `ECAL` opcode handler can now hold internal state. +#### Breaking + +- [#654](https://github.com/FuelLabs/fuel-vm/pull/654): Make public types versionable by making non-exhaustive. + ## [Version 0.43.2] ### Changed diff --git a/fuel-tx/src/transaction.rs b/fuel-tx/src/transaction.rs index ced4840ffc..7b0d8d2013 100644 --- a/fuel-tx/src/transaction.rs +++ b/fuel-tx/src/transaction.rs @@ -91,6 +91,7 @@ pub type TxId = Bytes32; #[derive(Debug, Clone, PartialEq, Eq, Hash, strum_macros::EnumCount)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[allow(clippy::large_enum_variant)] +#[non_exhaustive] pub enum Transaction { Script(Script), Create(Create), diff --git a/fuel-tx/src/transaction/types/input.rs b/fuel-tx/src/transaction/types/input.rs index eee7944c0c..df07d1fdbb 100644 --- a/fuel-tx/src/transaction/types/input.rs +++ b/fuel-tx/src/transaction/types/input.rs @@ -181,6 +181,7 @@ where #[derive(Debug, Clone, PartialEq, Eq, Hash, strum_macros::EnumCount)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[non_exhaustive] pub enum Input { CoinSigned(CoinSigned), CoinPredicate(CoinPredicate), diff --git a/fuel-tx/src/transaction/types/output.rs b/fuel-tx/src/transaction/types/output.rs index 37fb79c340..211a082b84 100644 --- a/fuel-tx/src/transaction/types/output.rs +++ b/fuel-tx/src/transaction/types/output.rs @@ -24,6 +24,7 @@ pub use repr::OutputRepr; #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, strum_macros::EnumCount)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Deserialize, Serialize)] +#[non_exhaustive] pub enum Output { Coin { to: Address, diff --git a/fuel-tx/test-helpers/src/lib.rs b/fuel-tx/test-helpers/src/lib.rs index 811e45e7d3..8538b5ead8 100644 --- a/fuel-tx/test-helpers/src/lib.rs +++ b/fuel-tx/test-helpers/src/lib.rs @@ -52,10 +52,8 @@ mod use_std { Mint, Output, Script, - Transaction, TransactionBuilder, }; - use fuel_types::canonical::Deserialize; use rand::{ distributions::{ Distribution, @@ -91,45 +89,6 @@ mod use_std { let input_sampler = Uniform::from(0..Input::COUNT); let output_sampler = Uniform::from(0..Output::COUNT); - // Trick to enforce coverage of all variants in compile-time - // - // When and if a new variant is added, this implementation enforces it will be - // listed here. - let empty: [u8; 0] = []; - debug_assert!({ - Input::decode(&mut &empty[..]) - .map(|i| match i { - Input::CoinSigned(_) => (), - Input::CoinPredicate(_) => (), - Input::Contract(_) => (), - Input::MessageCoinSigned(_) => (), - Input::MessageCoinPredicate(_) => (), - Input::MessageDataSigned(_) => (), - Input::MessageDataPredicate(_) => (), - }) - .unwrap_or(()); - - Output::decode(&mut &empty[..]) - .map(|o| match o { - Output::Coin { .. } => (), - Output::Contract(_) => (), - Output::Change { .. } => (), - Output::Variable { .. } => (), - Output::ContractCreated { .. } => (), - }) - .unwrap_or(()); - - Transaction::decode(&mut &empty[..]) - .map(|t| match t { - Transaction::Script(_) => (), - Transaction::Create(_) => (), - Transaction::Mint(_) => (), - }) - .unwrap_or(()); - - true - }); - Self { rng, input_sampler, diff --git a/fuel-vm/src/checked_transaction.rs b/fuel-vm/src/checked_transaction.rs index 24137e4389..aaa71f24ac 100644 --- a/fuel-vm/src/checked_transaction.rs +++ b/fuel-vm/src/checked_transaction.rs @@ -180,6 +180,8 @@ pub enum CheckError { Validity(ValidityError), /// The predicate verification failed. PredicateVerificationFailed(PredicateVerificationFailed), + /// Transaction is of an unknown variant + UnknownVariant(alloc::string::String), } /// Performs checks for a transaction @@ -385,6 +387,7 @@ impl EstimatePredicates for Transaction { Transaction::Script(script) => script.estimate_predicates(params), Transaction::Create(create) => create.estimate_predicates(params), Transaction::Mint(_) => Ok(()), + _ => Err(CheckError::UnknownVariant(alloc::format!("{:?}", &self))), } } @@ -400,6 +403,7 @@ impl EstimatePredicates for Transaction { create.estimate_predicates_async::(params).await } Transaction::Mint(_) => Ok(()), + _ => Err(CheckError::UnknownVariant(alloc::format!("{:?}", &self))), } } } @@ -511,6 +515,7 @@ impl From> for CheckedTransaction { (Transaction::Script(_), _) => unreachable!(), (Transaction::Create(_), _) => unreachable!(), (Transaction::Mint(_), _) => unreachable!(), + (_, _) => unreachable!(), } } } @@ -590,28 +595,28 @@ impl IntoChecked for Transaction { block_height: BlockHeight, consensus_params: &ConsensusParameters, ) -> Result, CheckError> { - let (transaction, metadata) = match self { + match self { Transaction::Script(script) => { let (transaction, metadata) = script .into_checked_basic(block_height, consensus_params)? .into(); - (transaction.into(), metadata.into()) + Ok((transaction.into(), metadata.into())) } Transaction::Create(create) => { let (transaction, metadata) = create .into_checked_basic(block_height, consensus_params)? .into(); - (transaction.into(), metadata.into()) + Ok((transaction.into(), metadata.into())) } Transaction::Mint(mint) => { let (transaction, metadata) = mint .into_checked_basic(block_height, consensus_params)? .into(); - (transaction.into(), metadata.into()) + Ok((transaction.into(), metadata.into())) } - }; - - Ok(Checked::basic(transaction, metadata)) + _ => Err(CheckError::UnknownVariant(alloc::format!("{:?}", self))), + } + .map(|(transaction, metadata)| Checked::basic(transaction, metadata)) } } diff --git a/fuel-vm/src/checked_transaction/balances.rs b/fuel-vm/src/checked_transaction/balances.rs index f373e952cd..26ad38b909 100644 --- a/fuel-vm/src/checked_transaction/balances.rs +++ b/fuel-vm/src/checked_transaction/balances.rs @@ -63,6 +63,7 @@ where retryable_balance += *amount; } Input::Contract(_) => {} + _ => {} } }