Skip to content

Commit

Permalink
feat: Versionable Message (FuelLabs#1632)
Browse files Browse the repository at this point in the history
Related issues:
- FuelLabs#1552

This PR converts the `Message` struct to an enum that can house multiple
variants for versioning. Version variants contain an instance of a
versioned struct, e.g., `MessageV1`. The `Message` enum exposes getters
to the underlying data and abstracts the version. Setters are exposed
only in test environments to allow tests to set up `Messages` in
specific ways for the test.

---------

Co-authored-by: Green Baneling <[email protected]>
  • Loading branch information
Brandon Vrooman and xgreenx authored Jan 29, 2024
1 parent 33d3f96 commit 3fdd33d
Show file tree
Hide file tree
Showing 17 changed files with 227 additions and 91 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Description of the upcoming release here.
- [#1601](https://github.com/FuelLabs/fuel-core/pull/1601): Fix formatting in docs and check that `cargo doc` passes in the CI.

#### Breaking
- [#16232](https://github.com/FuelLabs/fuel-core/pull/1632): Make `Message` type a version-able enum
- [#1628](https://github.com/FuelLabs/fuel-core/pull/1628): Make `CompressedCoin` type a version-able enum
- [#1616](https://github.com/FuelLabs/fuel-core/pull/1616): Make `BlockHeader` type a version-able enum
- [#1614](https://github.com/FuelLabs/fuel-core/pull/1614): Use the default consensus key regardless of trigger mode. The change is breaking because it removes the `--dev-keys` argument. If the `debug` flag is set, the default consensus key will be used, regardless of the trigger mode.
Expand Down
22 changes: 12 additions & 10 deletions crates/chain-config/src/config/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ use crate::{
use fuel_core_storage::MerkleRoot;
use fuel_core_types::{
blockchain::primitives::DaBlockHeight,
entities::message::Message,
entities::message::{
Message,
MessageV1,
},
fuel_asm::Word,
fuel_crypto::Hasher,
fuel_types::{
Expand Down Expand Up @@ -42,27 +45,26 @@ pub struct MessageConfig {

impl From<MessageConfig> for Message {
fn from(msg: MessageConfig) -> Self {
Message {
MessageV1 {
sender: msg.sender,
recipient: msg.recipient,
nonce: msg.nonce,
amount: msg.amount,
data: msg.data,
da_height: msg.da_height,
}
.into()
}
}

impl GenesisCommitment for Message {
fn root(&self) -> anyhow::Result<MerkleRoot> {
let Self {
sender,
recipient,
nonce,
amount,
data,
da_height,
} = self;
let sender = self.sender();
let recipient = self.recipient();
let nonce = self.nonce();
let amount = self.amount();
let data = self.data();
let da_height = self.da_height();

let message_hash = *Hasher::default()
.chain(sender)
Expand Down
14 changes: 9 additions & 5 deletions crates/fuel-core/src/coins_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,7 +251,10 @@ mod tests {
Coin,
CompressedCoin,
},
message::Message,
message::{
Message,
MessageV1,
},
},
fuel_asm::Word,
fuel_tx::*,
Expand Down Expand Up @@ -783,7 +786,7 @@ mod tests {
let excluded_ids = db
.owned_messages(&owner)
.into_iter()
.filter(|message| message.amount == 5)
.filter(|message| message.amount() == 5)
.map(|message| CoinId::Message(*message.id()))
.collect_vec();

Expand All @@ -799,7 +802,7 @@ mod tests {
let excluded_ids = db
.owned_messages(&owner)
.into_iter()
.filter(|message| message.amount == 5)
.filter(|message| message.amount() == 5)
.map(|message| CoinId::Message(*message.id()))
.collect_vec();

Expand Down Expand Up @@ -965,14 +968,15 @@ mod tests {
let nonce = self.last_message_index.into();
self.last_message_index += 1;

let message = Message {
let message: Message = MessageV1 {
sender: Default::default(),
recipient: owner,
nonce,
amount,
data: vec![],
da_height: DaBlockHeight::from(1u64),
};
}
.into();

let db = &mut self.database;
StorageMutate::<Messages>::insert(db, message.id(), &message).unwrap();
Expand Down
22 changes: 11 additions & 11 deletions crates/fuel-core/src/database/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ impl StorageMutate<Messages> for Database {

// insert secondary record by owner
self.storage_as_mut::<OwnedMessageIds>()
.insert(&OwnedMessageKey::new(&value.recipient, key), &())?;
.insert(&OwnedMessageKey::new(value.recipient(), key), &())?;

Ok(result)
}
Expand All @@ -103,7 +103,7 @@ impl StorageMutate<Messages> for Database {

if let Some(message) = &result {
self.storage_as_mut::<OwnedMessageIds>()
.remove(&OwnedMessageKey::new(&message.recipient, key))?;
.remove(&OwnedMessageKey::new(message.recipient(), key))?;
}

Ok(result)
Expand Down Expand Up @@ -155,12 +155,12 @@ impl Database {
let msg = msg?;

Ok(MessageConfig {
sender: msg.sender,
recipient: msg.recipient,
nonce: msg.nonce,
amount: msg.amount,
data: msg.data,
da_height: msg.da_height,
sender: *msg.sender(),
recipient: *msg.recipient(),
nonce: *msg.nonce(),
amount: msg.amount(),
data: msg.data().clone(),
da_height: msg.da_height(),
})
})
.collect::<StorageResult<Vec<MessageConfig>>>()?;
Expand Down Expand Up @@ -201,22 +201,22 @@ mod tests {
.unwrap();

// verify that 2 message IDs are associated with a single Owner/Recipient
let owned_msg_ids = db.owned_message_ids(&message.recipient, None, None);
let owned_msg_ids = db.owned_message_ids(message.recipient(), None, None);
assert_eq!(owned_msg_ids.count(), 2);

// remove the first message with its given id
let _ = db.storage_as_mut::<Messages>().remove(&first_id).unwrap();

// verify that only second ID is left
let owned_msg_ids: Vec<_> = db
.owned_message_ids(&message.recipient, None, None)
.owned_message_ids(message.recipient(), None, None)
.collect();
assert_eq!(owned_msg_ids.first().unwrap().as_ref().unwrap(), &second_id);
assert_eq!(owned_msg_ids.len(), 1);

// remove the second message with its given id
let _ = db.storage_as_mut::<Messages>().remove(&second_id).unwrap();
let owned_msg_ids = db.owned_message_ids(&message.recipient, None, None);
let owned_msg_ids = db.owned_message_ids(message.recipient(), None, None);
assert_eq!(owned_msg_ids.count(), 0);
}
}
26 changes: 15 additions & 11 deletions crates/fuel-core/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ mod tests {
},
entities::{
coins::coin::CompressedCoin,
message::Message,
message::{
Message,
MessageV1,
},
},
fuel_asm::{
op,
Expand Down Expand Up @@ -2225,7 +2228,7 @@ mod tests {
}

fn message_from_input(input: &Input, da_height: u64) -> Message {
Message {
MessageV1 {
sender: *input.sender().unwrap(),
recipient: *input.recipient().unwrap(),
nonce: *input.nonce().unwrap(),
Expand All @@ -2236,6 +2239,7 @@ mod tests {
.unwrap_or_default(),
da_height: DaBlockHeight(da_height),
}
.into()
}

/// Helper to build transactions and a message in it for some of the message tests
Expand Down Expand Up @@ -2331,8 +2335,8 @@ mod tests {

let exec = make_executor(&messages);
let view = exec.database_view_provider.latest_view();
assert!(!view.message_is_spent(&message_coin.nonce).unwrap());
assert!(!view.message_is_spent(&message_data.nonce).unwrap());
assert!(!view.message_is_spent(message_coin.nonce()).unwrap());
assert!(!view.message_is_spent(message_data.nonce()).unwrap());

let ExecutionResult {
skipped_transactions,
Expand All @@ -2349,8 +2353,8 @@ mod tests {

// Successful execution consumes `message_coin` and `message_data`.
let view = exec.database_view_provider.latest_view();
assert!(view.message_is_spent(&message_coin.nonce).unwrap());
assert!(view.message_is_spent(&message_data.nonce).unwrap());
assert!(view.message_is_spent(message_coin.nonce()).unwrap());
assert!(view.message_is_spent(message_data.nonce()).unwrap());
assert_eq!(
*view.coin(&UtxoId::new(tx_id, 0)).unwrap().amount(),
amount + amount
Expand Down Expand Up @@ -2385,8 +2389,8 @@ mod tests {

let exec = make_executor(&messages);
let view = exec.database_view_provider.latest_view();
assert!(!view.message_is_spent(&message_coin.nonce).unwrap());
assert!(!view.message_is_spent(&message_data.nonce).unwrap());
assert!(!view.message_is_spent(message_coin.nonce()).unwrap());
assert!(!view.message_is_spent(message_data.nonce()).unwrap());

let ExecutionResult {
skipped_transactions,
Expand All @@ -2403,8 +2407,8 @@ mod tests {

// We should spend only `message_coin`. The `message_data` should be unspent.
let view = exec.database_view_provider.latest_view();
assert!(view.message_is_spent(&message_coin.nonce).unwrap());
assert!(!view.message_is_spent(&message_data.nonce).unwrap());
assert!(view.message_is_spent(message_coin.nonce()).unwrap());
assert!(!view.message_is_spent(message_data.nonce()).unwrap());
assert_eq!(*view.coin(&UtxoId::new(tx_id, 0)).unwrap().amount(), amount);
}

Expand Down Expand Up @@ -2528,7 +2532,7 @@ mod tests {
let (tx, mut message) = make_tx_and_message(&mut rng, 0);

// Modifying the message to make it mismatch
message.amount = 123;
message.set_amount(123);

let mut block = Block::default();
*block.transactions_mut() = vec![tx.clone()];
Expand Down
2 changes: 1 addition & 1 deletion crates/fuel-core/src/query/balance/asset_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ impl<'a> AssetsQuery<'a> {
Ok(message)
})
})
.filter_ok(|message| message.data.is_empty())
.filter_ok(|message| message.data().is_empty())
.map(|result| {
result.map(|message| {
CoinType::MessageCoin(
Expand Down
14 changes: 7 additions & 7 deletions crates/fuel-core/src/schema/message.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,27 +38,27 @@ pub struct Message(pub(crate) entities::message::Message);
#[Object]
impl Message {
async fn amount(&self) -> U64 {
self.0.amount.into()
self.0.amount().into()
}

async fn sender(&self) -> Address {
self.0.sender.into()
(*self.0.sender()).into()
}

async fn recipient(&self) -> Address {
self.0.recipient.into()
(*self.0.recipient()).into()
}

async fn nonce(&self) -> Nonce {
self.0.nonce.into()
(*self.0.nonce()).into()
}

async fn data(&self) -> HexString {
self.0.data.clone().into()
self.0.data().clone().into()
}

async fn da_height(&self) -> U64 {
self.0.da_height.as_u64().into()
self.0.da_height().as_u64().into()
}
}

Expand Down Expand Up @@ -108,7 +108,7 @@ impl MessageQuery {

let messages = messages.map(|result| {
result
.map(|message| (message.nonce.into(), message.into()))
.map(|message| ((*message.nonce()).into(), message.into()))
.map_err(Into::into)
});

Expand Down
10 changes: 7 additions & 3 deletions crates/fuel-core/src/service/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ use fuel_core_types::{
CompressedCoinV1,
},
contract::ContractUtxoInfo,
message::Message,
message::{
Message,
MessageV1,
},
},
fuel_merkle::binary,
fuel_tx::{
Expand Down Expand Up @@ -331,14 +334,15 @@ fn init_da_messages(
if let Some(state) = &state {
if let Some(message_state) = &state.messages {
for msg in message_state {
let message = Message {
let message: Message = MessageV1 {
sender: msg.sender,
recipient: msg.recipient,
nonce: msg.nonce,
amount: msg.amount,
data: msg.data.clone(),
da_height: msg.da_height,
};
}
.into();

if db
.storage::<Messages>()
Expand Down
2 changes: 1 addition & 1 deletion crates/services/executor/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1125,7 +1125,7 @@ where
.get_message(nonce, &block_da_height)
.map_err(|e| ExecutorError::RelayerError(e.into()))?
{
if message.da_height > block_da_height {
if message.da_height() > block_da_height {
return Err(TransactionValidityError::MessageSpendTooEarly(
*nonce,
)
Expand Down
8 changes: 6 additions & 2 deletions crates/services/relayer/src/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ use ethers_core::{
};
use fuel_core_types::{
blockchain::primitives::DaBlockHeight,
entities::message::Message,
entities::message::{
Message,
MessageV1,
},
fuel_types::{
Address,
Nonce,
Expand All @@ -31,14 +34,15 @@ pub struct MessageLog {

impl From<&MessageLog> for Message {
fn from(message: &MessageLog) -> Self {
Self {
MessageV1 {
sender: message.sender,
recipient: message.recipient,
nonce: message.nonce,
amount: message.amount,
data: message.data.clone(),
da_height: message.da_height,
}
.into()
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/services/relayer/src/mock_db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl RelayerDb for MockDb {
let mut m = self.data.lock().unwrap();
for message in messages {
m.messages
.entry(message.da_height)
.entry(message.da_height())
.or_default()
.insert(*message.id(), message.clone());
}
Expand Down
2 changes: 1 addition & 1 deletion crates/services/relayer/src/ports.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ where
for message in messages {
db.storage::<Messages>().insert(message.id(), message)?;
let max = max_height.get_or_insert(0u64);
*max = (*max).max(message.da_height.0);
*max = (*max).max(message.da_height().0);
}
if let Some(height) = max_height {
if **da_height < height {
Expand Down
Loading

0 comments on commit 3fdd33d

Please sign in to comment.