diff --git a/CHANGELOG.md b/CHANGELOG.md index e6f4f5a033..e723b58754 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ Description of the upcoming release here. - [#1577](https://github.com/FuelLabs/fuel-core/pull/1577): Moved insertion of sealed blocks into the `BlockImporter` instead of the executor. #### Breaking +- [#1593](https://github.com/FuelLabs/fuel-core/pull/1593) Make `Block` type a version-able enum - [#1573](https://github.com/FuelLabs/fuel-core/pull/1573): Remove nested p2p request/response encoding. Only breaks p2p networking compatibility with older fuel-core versions, but is otherwise fully internal. ## [Version 0.22.0] diff --git a/crates/types/src/blockchain/block.rs b/crates/types/src/blockchain/block.rs index 30f7013f99..521ad5516e 100644 --- a/crates/types/src/blockchain/block.rs +++ b/crates/types/src/blockchain/block.rs @@ -25,11 +25,27 @@ use crate::{ }, }; +/// Version-able block type +#[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[non_exhaustive] +pub enum Block { + /// V1 Block + V1(BlockV1), +} + +#[cfg(any(test, feature = "test-helpers"))] +impl Default for Block { + fn default() -> Self { + Block::V1(BlockV1::default()) + } +} + /// Fuel block with all transaction data included #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(any(test, feature = "test-helpers"), derive(Default))] -pub struct Block { +pub struct BlockV1 { /// Generated complete header. header: BlockHeader, /// Executed transactions. @@ -70,10 +86,11 @@ impl Block { transactions: Vec, message_ids: &[MessageId], ) -> Self { - Self { + let inner = BlockV1 { header: header.generate(&transactions, message_ids), transactions, - } + }; + Block::V1(inner) } /// Try creating a new full fuel block from a [`BlockHeader`] and @@ -83,17 +100,29 @@ impl Block { header: BlockHeader, transactions: Vec, ) -> Option { - header.validate_transactions(&transactions).then_some(Self { - header, - transactions, - }) + header + .validate_transactions(&transactions) + .then_some(Block::V1(BlockV1 { + header, + transactions, + })) } /// Compresses the fuel block and replaces transactions with hashes. pub fn compress(&self, chain_id: &ChainId) -> CompressedBlock { - Block { - header: self.header.clone(), - transactions: self.transactions.iter().map(|tx| tx.id(chain_id)).collect(), + match self { + Block::V1(inner) => { + let transactions = inner + .transactions + .iter() + .map(|tx| tx.id(chain_id)) + .collect(); + let new_inner = BlockV1 { + header: inner.header.clone(), + transactions, + }; + Block::V1(new_inner) + } } } } @@ -101,7 +130,12 @@ impl Block { impl Block { /// Destructure into the inner types. pub fn into_inner(self) -> (BlockHeader, Vec) { - (self.header, self.transactions) + match self { + Block::V1(BlockV1 { + header, + transactions, + }) => (header, transactions), + } } } @@ -110,9 +144,11 @@ impl CompressedBlock { pub fn uncompress(self, transactions: Vec) -> Block { // TODO: should we perform an extra validation step to ensure the provided // txs match the expected ones in the block? - Block { - header: self.header, - transactions, + match self { + Block::V1(inner) => Block::V1(BlockV1 { + header: inner.header, + transactions, + }), } } } @@ -125,35 +161,43 @@ impl Block { // identifier on the fly. // // This assertion is a double-checks that this behavior is not changed. - debug_assert_eq!(self.header.id(), self.header.hash()); - self.header.id() + debug_assert_eq!(self.header().id(), self.header().hash()); + self.header().id() } /// Get the executed transactions. pub fn transactions(&self) -> &[TransactionRepresentation] { - &self.transactions[..] + match self { + Block::V1(inner) => &inner.transactions, + } } /// Get the complete header. pub fn header(&self) -> &BlockHeader { - &self.header + match self { + Block::V1(inner) => &inner.header, + } } /// The type of consensus this header is using. pub fn consensus_type(&self) -> ConsensusType { - self.header.consensus_type() + self.header().consensus_type() } /// Get mutable access to transactions for testing purposes #[cfg(any(test, feature = "test-helpers"))] pub fn transactions_mut(&mut self) -> &mut Vec { - &mut self.transactions + match self { + Block::V1(inner) => &mut inner.transactions, + } } /// Get mutable access to header for testing purposes #[cfg(any(test, feature = "test-helpers"))] pub fn header_mut(&mut self) -> &mut BlockHeader { - &mut self.header + match self { + Block::V1(inner) => &mut inner.header, + } } } @@ -180,35 +224,36 @@ impl PartialFuelBlock { impl From for PartialFuelBlock { fn from(block: Block) -> Self { - let Block { - header: - BlockHeader { - application: ApplicationHeader { da_height, .. }, - consensus: - ConsensusHeader { - prev_root, - height, - time, - .. - }, - .. - }, - transactions, - } = block; - Self { - header: PartialBlockHeader { - application: ApplicationHeader { - da_height, - generated: Empty {}, - }, - consensus: ConsensusHeader { - prev_root, - height, - time, - generated: Empty {}, + match block { + Block::V1(BlockV1 { + header: + BlockHeader { + application: ApplicationHeader { da_height, .. }, + consensus: + ConsensusHeader { + prev_root, + height, + time, + .. + }, + .. + }, + transactions, + }) => Self { + header: PartialBlockHeader { + application: ApplicationHeader { + da_height, + generated: Empty {}, + }, + consensus: ConsensusHeader { + prev_root, + height, + time, + generated: Empty {}, + }, }, + transactions, }, - transactions, } } } @@ -217,9 +262,10 @@ impl From for PartialFuelBlock { impl CompressedBlock { /// Create a compressed header for testing. This does not generate fields. pub fn test(header: BlockHeader, transactions: Vec) -> Self { - Self { + let inner = BlockV1 { header, transactions, - } + }; + Self::V1(inner) } }