Skip to content

Commit

Permalink
Make Block versionable (FuelLabs#1593)
Browse files Browse the repository at this point in the history
  • Loading branch information
MitchTurner authored Jan 9, 2024
1 parent 36528a9 commit e1e6319
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 50 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
146 changes: 96 additions & 50 deletions crates/types/src/blockchain/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<TransactionRepresentation = Transaction> {
/// V1 Block
V1(BlockV1<TransactionRepresentation>),
}

#[cfg(any(test, feature = "test-helpers"))]
impl<T: Default> Default for Block<T> {
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<TransactionRepresentation = Transaction> {
pub struct BlockV1<TransactionRepresentation = Transaction> {
/// Generated complete header.
header: BlockHeader,
/// Executed transactions.
Expand Down Expand Up @@ -70,10 +86,11 @@ impl Block<Transaction> {
transactions: Vec<Transaction>,
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
Expand All @@ -83,25 +100,42 @@ impl Block<Transaction> {
header: BlockHeader,
transactions: Vec<Transaction>,
) -> Option<Self> {
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)
}
}
}
}

impl<T> Block<T> {
/// Destructure into the inner types.
pub fn into_inner(self) -> (BlockHeader, Vec<T>) {
(self.header, self.transactions)
match self {
Block::V1(BlockV1 {
header,
transactions,
}) => (header, transactions),
}
}
}

Expand All @@ -110,9 +144,11 @@ impl CompressedBlock {
pub fn uncompress(self, transactions: Vec<Transaction>) -> Block<Transaction> {
// 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,
}),
}
}
}
Expand All @@ -125,35 +161,43 @@ impl<TransactionRepresentation> Block<TransactionRepresentation> {
// 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<TransactionRepresentation> {
&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,
}
}
}

Expand All @@ -180,35 +224,36 @@ impl PartialFuelBlock {

impl From<Block> 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,
}
}
}
Expand All @@ -217,9 +262,10 @@ impl From<Block> for PartialFuelBlock {
impl CompressedBlock {
/// Create a compressed header for testing. This does not generate fields.
pub fn test(header: BlockHeader, transactions: Vec<TxId>) -> Self {
Self {
let inner = BlockV1 {
header,
transactions,
}
};
Self::V1(inner)
}
}

0 comments on commit e1e6319

Please sign in to comment.