Skip to content

Commit

Permalink
Handle new state transition bytecode and new consensus parameter vers…
Browse files Browse the repository at this point in the history
…ion (#2621)

on on upgrade transaction

Closes #2584

Questions for the reviewers: 

- [ ] I am assuming that the latest known state transition bytecode
version and latest known consensus parameters versions will be loaded
from the storage when the global root service starts, and will be passed
to the proces_block function through the `UpdateMerklizedTables` trait.
Is this reasonable?
- [ ] I am revalidating the upgrade transaction metadata, but I am not
sure if this is needed?
- [ ] I am assuming that both state transition bytecode version and
consensus parameters version increment by 1 when an upgrade transaction
with the corresponding purpose is processed, is this correct?




## Linked Issues/PRs
<!-- List of related issues/PRs -->

## Description
<!-- List of detailed changes -->

## Checklist
- [ ] Breaking changes are clearly marked as such in the PR description
and changelog
- [ ] New behavior is reflected in tests
- [ ] [The specification](https://github.com/FuelLabs/fuel-specs/)
matches the implemented behavior (link update PR if changes are needed)

### Before requesting review
- [ ] I have reviewed the code myself
- [ ] I have created follow-up issues caused by this PR and linked them
here

### After merging, notify other teams

[Add or remove entries as needed]

- [ ] [Rust SDK](https://github.com/FuelLabs/fuels-rs/)
- [ ] [Sway compiler](https://github.com/FuelLabs/sway/)
- [ ] [Platform
documentation](https://github.com/FuelLabs/devrel-requests/issues/new?assignees=&labels=new+request&projects=&template=NEW-REQUEST.yml&title=%5BRequest%5D%3A+)
(for out-of-organization contributors, the person merging the PR will do
this)
- [ ] Someone else?

---------

Co-authored-by: Mårten Blankfors <marten@blankfors.se>
Co-authored-by: green <xgreenx9999@gmail.com>
  • Loading branch information
3 people authored Feb 5, 2025
1 parent a7e20df commit f3bb87a
Show file tree
Hide file tree
Showing 4 changed files with 196 additions and 7 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added
- [2668](https://github.com/FuelLabs/fuel-core/pull/2668): Expose gas price service test helpers
- [2621](https://github.com/FuelLabs/fuel-core/pull/2598): Global merkle root storage updates process upgrade transactions.

## [Version 0.41.5]

Expand Down
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion crates/fraud_proofs/global_merkle_root/storage/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,13 @@ strum = { workspace = true }
strum_macros = { workspace = true }

[dev-dependencies]
fuel-core-storage = { workspace = true, default-features = false, features = [
fuel-core-storage = { workspace = true, features = ["alloc", "test-helpers"] }
fuel-core-types = { workspace = true, features = [
"serde",
"alloc",
"test-helpers",
] }
postcard = { workspace = true, features = ["alloc"] }
rand = { workspace = true }

[features]
Expand Down
196 changes: 190 additions & 6 deletions crates/fraud_proofs/global_merkle_root/storage/src/update.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
use crate::{
column::Column,
Coins,
ConsensusParametersVersions,
ContractsLatestUtxo,
Messages,
StateTransitionBytecodeVersions,
};
use alloc::{
borrow::Cow,
Expand All @@ -15,7 +17,13 @@ use fuel_core_storage::{
StorageAsMut,
};
use fuel_core_types::{
blockchain::block::Block,
blockchain::{
block::Block,
header::{
ConsensusParametersVersion,
StateTransitionBytecodeVersion,
},
},
entities::{
coins::coin::CompressedCoinV1,
contract::ContractUtxoInfo,
Expand All @@ -27,6 +35,7 @@ use fuel_core_types::{
Inputs,
OutputContract,
Outputs,
UpgradePurpose as _,
},
input::{
self,
Expand All @@ -51,6 +60,9 @@ use fuel_core_types::{
Transaction,
TxPointer,
UniqueIdentifier,
Upgrade,
UpgradeMetadata,
UpgradePurpose,
UtxoId,
},
fuel_types::{
Expand Down Expand Up @@ -83,6 +95,12 @@ where
let mut update_transaction = UpdateMerkleizedTablesTransaction {
chain_id,
storage: self,
latest_state_transition_bytecode_version: block
.header()
.state_transition_bytecode_version,
latest_consensus_parameters_version: block
.header()
.consensus_parameters_version,
};

update_transaction.process_block(block)?;
Expand All @@ -94,6 +112,8 @@ where
struct UpdateMerkleizedTablesTransaction<'a, Storage> {
chain_id: ChainId,
storage: &'a mut StorageTransaction<Storage>,
latest_consensus_parameters_version: ConsensusParametersVersion,
latest_state_transition_bytecode_version: StateTransitionBytecodeVersion,
}

impl<'a, Storage> UpdateMerkleizedTablesTransaction<'a, Storage>
Expand Down Expand Up @@ -134,8 +154,10 @@ where
self.process_output(tx_pointer, utxo_id, &inputs, output)?;
}

if let Transaction::Upgrade(tx) = tx {
self.process_upgrade_transaction(tx)?;
}
// TODO(#2583): Add the transaction to the `ProcessedTransactions` table.
// TODO(#2584): Insert state transition bytecode and consensus parameter updates.
// TODO(#2585): Insert uplodade bytecodes.
// TODO(#2586): Insert blobs.
// TODO(#2587): Insert raw code for created contracts.
Expand Down Expand Up @@ -267,6 +289,55 @@ where
}
Ok(())
}

fn process_upgrade_transaction(&mut self, tx: &Upgrade) -> anyhow::Result<()> {
let metadata = match tx.metadata() {
Some(metadata) => metadata.body.clone(),
None => UpgradeMetadata::compute(tx).map_err(|e| anyhow::anyhow!(e))?,
};

match metadata {
UpgradeMetadata::ConsensusParameters {
consensus_parameters,
calculated_checksum: _,
} => {
let Some(next_consensus_parameters_version) =
self.latest_consensus_parameters_version.checked_add(1)
else {
return Err(anyhow::anyhow!("Invalid consensus parameters version"));
};
self.latest_consensus_parameters_version =
next_consensus_parameters_version;
self.storage
.storage::<ConsensusParametersVersions>()
.insert(
&self.latest_consensus_parameters_version,
&consensus_parameters,
)?;
}
UpgradeMetadata::StateTransition => match tx.upgrade_purpose() {
UpgradePurpose::ConsensusParameters { .. } => unreachable!(
"Upgrade with StateTransition metadata should have StateTransition purpose"
),
UpgradePurpose::StateTransition { root } => {
let Some(next_state_transition_bytecode_version) =
self.latest_state_transition_bytecode_version.checked_add(1)
else {
return Err(anyhow::anyhow!(
"Invalid state transition bytecode version"
));
};
self.latest_state_transition_bytecode_version =
next_state_transition_bytecode_version;
self.storage
.storage::<StateTransitionBytecodeVersions>()
.insert(&self.latest_state_transition_bytecode_version, root)?;
}
},
}

Ok(())
}
}

pub trait TransactionInputs {
Expand Down Expand Up @@ -320,10 +391,17 @@ mod tests {
},
StorageAsRef,
};
use fuel_core_types::fuel_tx::{
Bytes32,
ContractId,
TxId,
use fuel_core_types::{
fuel_crypto::Hasher,
fuel_tx::{
Bytes32,
ConsensusParameters,
ContractId,
Finalizable,
TransactionBuilder,
TxId,
Witness,
},
};

use rand::{
Expand Down Expand Up @@ -528,6 +606,92 @@ mod tests {
assert!(coin_doesnt_exist_after_process_input);
}

#[test]
fn process_upgrade_transaction_should_update_latest_state_transition_bytecode_version_when_interacting_with_relevant_upgrade(
) {
// Given
let new_root = Bytes32::from([1; 32]);
let upgrade_tx = TransactionBuilder::upgrade(UpgradePurpose::StateTransition {
root: new_root,
})
.finalize();

let mut storage = InMemoryStorage::default();

// When
let state_transition_bytecode_version_before_upgrade = 1;
let state_transition_bytecode_version_after_upgrade =
state_transition_bytecode_version_before_upgrade + 1;

let mut storage_tx = storage.write_transaction();
let mut update_tx = storage_tx
.construct_update_merkleized_tables_transaction_with_versions(
state_transition_bytecode_version_before_upgrade,
0,
);
update_tx.process_upgrade_transaction(&upgrade_tx).unwrap();

let state_transition_bytecode_root_after_upgrade = storage_tx
.storage_as_ref::<StateTransitionBytecodeVersions>()
.get(&state_transition_bytecode_version_after_upgrade)
.expect("In memory Storage should not return an error")
.expect("State transition bytecode version after upgrade should be present")
.into_owned();

// Then
assert_eq!(state_transition_bytecode_version_before_upgrade, 1);
assert_eq!(state_transition_bytecode_version_after_upgrade, 2);
assert_eq!(state_transition_bytecode_root_after_upgrade, new_root);
}

#[test]
fn process_upgrade_transaction_should_update_latest_consensus_parameters_version_when_interacting_with_relevant_upgrade(
) {
// Given
let consensus_parameters = ConsensusParameters::default();
let serialized_consensus_parameters =
postcard::to_allocvec(&consensus_parameters)
.expect("Consensus parameters serialization should succeed");
let tx_witness = Witness::from(serialized_consensus_parameters.clone());
let serialized_witness = tx_witness.as_vec();
let checksum = Hasher::hash(serialized_witness);
let upgrade_tx =
TransactionBuilder::upgrade(UpgradePurpose::ConsensusParameters {
witness_index: 0,
checksum,
})
.add_witness(tx_witness)
.finalize();

let mut storage = InMemoryStorage::default();

// When
let consensus_parameters_version_before_upgrade = 1;
let consensus_parameters_version_after_upgrade =
consensus_parameters_version_before_upgrade + 1;

let mut storage_tx = storage.write_transaction();
let mut update_tx = storage_tx
.construct_update_merkleized_tables_transaction_with_versions(
0,
consensus_parameters_version_before_upgrade,
);

update_tx.process_upgrade_transaction(&upgrade_tx).unwrap();

let consensus_parameters_after_upgrade = storage_tx
.storage_as_ref::<ConsensusParametersVersions>()
.get(&consensus_parameters_version_after_upgrade)
.expect("In memory Storage should not return an error")
.expect("State transition bytecode version after upgrade should be present")
.into_owned();

// Then
assert_eq!(consensus_parameters_version_before_upgrade, 1);
assert_eq!(consensus_parameters_version_after_upgrade, 2);
assert_eq!(consensus_parameters_after_upgrade, consensus_parameters);
}

fn random_utxo_id(rng: &mut impl rand::RngCore) -> UtxoId {
let mut txid = TxId::default();
rng.fill_bytes(txid.as_mut());
Expand Down Expand Up @@ -562,6 +726,12 @@ mod tests {
fn construct_update_merkleized_tables_transaction(
self,
) -> UpdateMerkleizedTablesTransaction<'a, Self::Storage>;

fn construct_update_merkleized_tables_transaction_with_versions(
self,
latest_state_transition_bytecode_version: StateTransitionBytecodeVersion,
latest_consensus_parameters_version: ConsensusParametersVersion,
) -> UpdateMerkleizedTablesTransaction<'a, Self::Storage>;
}

impl<'a, Storage> ConstructUpdateMerkleizedTablesTransactionForTests<'a>
Expand All @@ -575,6 +745,20 @@ mod tests {
UpdateMerkleizedTablesTransaction {
chain_id: ChainId::default(),
storage: self,
latest_consensus_parameters_version: Default::default(),
latest_state_transition_bytecode_version: Default::default(),
}
}
fn construct_update_merkleized_tables_transaction_with_versions(
self,
latest_state_transition_bytecode_version: StateTransitionBytecodeVersion,
latest_consensus_parameters_version: ConsensusParametersVersion,
) -> UpdateMerkleizedTablesTransaction<'a, Self::Storage> {
UpdateMerkleizedTablesTransaction {
chain_id: ChainId::default(),
storage: self,
latest_consensus_parameters_version,
latest_state_transition_bytecode_version,
}
}
}
Expand Down

0 comments on commit f3bb87a

Please sign in to comment.