Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

A new Upgrade transaction to perform network upgrades #707

Merged
merged 45 commits into from
Apr 9, 2024
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
cb9d324
Versioned `GasCosts`
xgreenx Mar 21, 2024
2feab92
Versioned `ConsensusParameters`ю
xgreenx Mar 21, 2024
57c7730
Updated CHANGELOG.md
xgreenx Mar 21, 2024
41a537c
Versioned `FeeParameters`
xgreenx Mar 21, 2024
83721d9
Versioned `PredicateParameters`, `ScriptParameters`, `ContractParamet…
xgreenx Mar 21, 2024
ed2e94b
Versioned `TxParameters`
xgreenx Mar 21, 2024
34aa7dc
Updated CHANGELOG.md
xgreenx Mar 21, 2024
0ca4ddf
Make CI happy
xgreenx Mar 21, 2024
38e515d
Merge branch 'master' into feature/versioning-sub-parameters
xgreenx Mar 21, 2024
5c5b009
Reshuffled fields `Script` and `Create` transactions to unify part us…
xgreenx Mar 22, 2024
5eae221
Updated CHANGELOG.md
xgreenx Mar 22, 2024
bd12db3
Merge branch 'master' into feature/versioning-sub-parameters
xgreenx Mar 22, 2024
a3618cc
Merge branch 'feature/versioning-sub-parameters' into feature/common-…
xgreenx Mar 22, 2024
edc0c1d
Added privileged address to the `ConsensusParameters`
xgreenx Mar 23, 2024
a015fcc
Updated CHANGELOG.md
xgreenx Mar 23, 2024
b57047a
Unified `Create` and `Script` logic via `ChargeableTransaction`
xgreenx Mar 24, 2024
3ebe1d8
Updated CHANGELOG.md
xgreenx Mar 24, 2024
8f8fdf0
Merge branch 'feature/privileged-address' into feature/upgrade-transa…
xgreenx Mar 24, 2024
27d18ac
Merge branch 'master' into feature/versioning-sub-parameters
xgreenx Mar 25, 2024
2f2cfdc
Merge branch 'feature/versioning-sub-parameters' into feature/common-…
xgreenx Mar 25, 2024
13592ac
Merge branch 'feature/common-payable-part' into feature/chargeable-tr…
xgreenx Mar 25, 2024
fa4c795
A new `Upgrade` transaction to perform network upgrades
xgreenx Mar 25, 2024
cbee779
Merge branch 'feature/chargeable-transaction' into feature/upgrade-tr…
xgreenx Mar 25, 2024
e374ea3
Merge branch 'master' into feature/versioning-sub-parameters
xgreenx Mar 25, 2024
c4cbc5f
Merge branch 'feature/versioning-sub-parameters' into feature/common-…
xgreenx Mar 25, 2024
6db8b16
Merge branch 'feature/common-payable-part' into feature/chargeable-tr…
xgreenx Mar 25, 2024
d5532d0
Merge branch 'feature/chargeable-transaction' into feature/upgrade-tr…
xgreenx Mar 25, 2024
f9f2f39
Merge branch 'master' into feature/common-payable-part
xgreenx Mar 25, 2024
0fbcb44
Merge branch 'master' into feature/common-payable-part
xgreenx Mar 25, 2024
50502cf
Merge branch 'feature/common-payable-part' into feature/chargeable-tr…
xgreenx Mar 26, 2024
87424ec
Merge branch 'feature/chargeable-transaction' into feature/upgrade-tr…
xgreenx Mar 26, 2024
4496d2b
Update fuel-tx/src/transaction/id.rs
xgreenx Mar 26, 2024
f975aab
Merge branch 'master' into feature/chargeable-transaction
xgreenx Mar 26, 2024
09327bd
Merge branch 'feature/chargeable-transaction' into feature/upgrade-tr…
Dentosal Mar 26, 2024
652157e
Merge branch 'master' into feature/upgrade-transaction
xgreenx Apr 1, 2024
080e73c
Added tests required for any transaction
xgreenx Apr 1, 2024
0b815be
Updated CHANGELOG.md
xgreenx Apr 3, 2024
68a41da
Updated CHANGELOG.md
xgreenx Apr 3, 2024
919560d
Updated CHANGELOG.md
xgreenx Apr 3, 2024
3510e37
Added a comment
xgreenx Apr 4, 2024
bb585a7
Merge branch 'master' into feature/upgrade-transaction
xgreenx Apr 5, 2024
71c026c
Merge branch 'master' into feature/upgrade-transaction
xgreenx Apr 6, 2024
4771d5a
Use right discriminant for the `Upgrade` transaction
xgreenx Apr 7, 2024
29aa53b
Applied comments from PR
xgreenx Apr 9, 2024
120de10
Removed iow
xgreenx Apr 9, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,72 @@ and this project adheres to [Semantic Versioning](http://semver.org/).

### Added

#### Breaking

- [#707](https://github.com/FuelLabs/fuel-vm/pull/707): The change adds a new `Upgrade` transaction that allows upgrading either consensus parameters or state transition function used by the network to produce future blocks.
The purpose of the upgrade is defined by the `Upgrade Purpose` type:

```rust
pub enum UpgradePurpose {
/// The upgrade is performed to change the consensus parameters.
ConsensusParameters {
/// The index of the witness in the [`Witnesses`] field that contains
/// the serialized consensus parameters.
witness_index: u16,
/// The hash of the serialized consensus parameters.
/// Since the serialized consensus parameters live inside witnesses(malleable
/// data), any party can override them. The `checksum` is used to verify that the
/// data was not modified.
checksum: Bytes32,
},
/// The upgrade is performed to change the state transition function.
StateTransition {
/// The hash of the new bytecode of the state transition function.
/// The bytecode must be present on the blockchain(should be known by the
/// network) at the moment of inclusion of this transaction.
bytecode_hash: Bytes32,
},
}
```

The `Upgrade` transaction is chargeable, and the sender should pay for it. Transaction inputs should contain only base assets.

Only the privileged address can upgrade the network. The privileged address can be either a real account or a predicate.

Since serialized consensus parameters are small(< 2kb), they can be part of the upgrade transaction and live inside of witness data. The bytecode of the blockchain state transition function is huge ~1.6MB(relative to consensus parameters), and it is impossible to fit it into one transaction. So when we perform the upgrade of the state transition function, it should already be available on the blockchain. The transaction to actually upload the bytecode(`Upload` transaction) will implemented in the https://github.com/FuelLabs/fuel-core/issues/1754.

### Changed

- [#707](https://github.com/FuelLabs/fuel-vm/pull/707): Used the same pattern everywhere in the codebase:
```rust
Self::Script(tx) => tx.encode_static(buffer),
Self::Create(tx) => tx.encode_static(buffer),
Self::Mint(tx) => tx.encode_static(buffer),
Self::Upgrade(tx) => tx.encode_static(buffer),
```

Instead of:
```rust
Transaction::Script(script) => script.encode_static(buffer),
Transaction::Create(create) => create.encode_static(buffer),
Transaction::Mint(mint) => mint.encode_static(buffer),
Transaction::Upgrade(upgrade) => upgrade.encode_static(buffer),
```

#### Breaking

- [#707](https://github.com/FuelLabs/fuel-vm/pull/707): Side small breaking for tests changes from the `Upgrade` transaction:
- Moved `fuel-tx-test-helpers` logic into the `fuel_tx::test_helpers` module.
- Added a new rule for `Create` transaction: all inputs should use base asset otherwise it returns `TransactionInputContainsNonBaseAssetId` error.
- Renamed some errors because now they are used for several transactions(`Upgrade` uses some errors from `Create` and some from `Script` transactions):
- `TransactionScriptOutputContractCreated` -> `TransactionOutputContainsContractCreated`.
- `TransactionCreateOutputContract` -> `TransactionOutputContainsContract`.
- `TransactionCreateOutputVariable` -> `TransactionOutputContainsVariable`.
- `TransactionCreateOutputChangeNotBaseAsset` -> `TransactionChangeChangeUsesNotBaseAsset`.
- `TransactionCreateInputContract` -> `TransactionInputContainsContract`.
- `TransactionCreateMessageData` -> `TransactionInputContainsMessageData`.
- The combination of `serde` and `postcard` is used to serialize and deserialize `ConsensusParameters` during the upgrade. This means the protocol and state transition function requires the `serde` feature by default for `ConsensusParameters` and `fuel-types`.

- [#697](https://github.com/FuelLabs/fuel-vm/pull/697): Changed the VM to internally use separate buffers for the stack and the heap to improve startup time. After this change, memory that was never part of the stack or the heap cannot be accessed, even for reading. Also, even if the whole memory is allocated, accesses spanning from the stack to the heap are not allowed. This PR also fixes a bug that required one-byte gap between the stack and the heap. Multiple errors have been changed to be more sensible ones, and sometimes the order of which error is returned has changed. `ALOC` opcode now zeroes the newly allocated memory.

## [Version 0.48.0]
Expand Down
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ members = [
"fuel-merkle",
"fuel-storage",
"fuel-tx",
"fuel-tx/test-helpers",
"fuel-types",
"fuel-vm",
]
Expand Down
10 changes: 5 additions & 5 deletions fuel-tx/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,13 @@ derive_more = { version = "0.99", default-features = false, features = ["display
fuel-asm = { workspace = true, default-features = false }
fuel-crypto = { workspace = true, default-features = false }
fuel-merkle = { workspace = true, default-features = false, optional = true }
fuel-types = { workspace = true, default-features = false }
fuel-types = { workspace = true, default-features = false, features = ["serde"] }
hashbrown = { version = "0.14", optional = true }
itertools = { version = "0.10", default-features = false, optional = true }
js-sys = { version = "0.3", optional = true }
postcard = { version = "1.0", features = ["alloc"] }
rand = { version = "0.8", default-features = false, features = ["std_rng"], optional = true }
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"], optional = true }
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
serde-wasm-bindgen = { version = "0.6", optional = true }
serde_json = { version = "1.0", default-features = false, features = ["alloc"], optional = true }
strum = { version = "0.24", default-features = false, optional = true }
Expand All @@ -33,7 +34,6 @@ wasm-bindgen = { version = "0.2.88", optional = true }
bincode = { workspace = true }
fuel-crypto = { workspace = true, default-features = false, features = ["random"] }
fuel-tx = { path = ".", features = ["random", "serde", "test-helpers"] }
fuel-tx-test-helpers = { path = "test-helpers" }
fuel-types = { workspace = true, default-features = false, features = ["random"] }
hex = { version = "0.4", default-features = false }
insta = "1.0"
Expand All @@ -49,7 +49,7 @@ test-helpers = ["alloc", "internals"]
internals = []
typescript = ["alloc", "js-sys", "wasm-bindgen", "serde", "serde-wasm-bindgen", "fuel-types/typescript"]
random = ["fuel-crypto/random", "fuel-types/random", "rand"]
std = ["alloc", "fuel-asm/std", "fuel-crypto/std", "fuel-merkle/std", "fuel-types/std", "itertools/default", "rand?/default", "serde?/default", "hex/std"]
std = ["alloc", "fuel-asm/std", "fuel-crypto/std", "fuel-merkle/std", "fuel-types/std", "itertools/default", "rand?/default", "serde/default", "hex/std"]
alloc = ["hashbrown", "fuel-types/alloc", "itertools/use_alloc", "derivative", "fuel-merkle", "strum", "strum_macros"]
# serde is requiring alloc because its mandatory for serde_json. to avoid adding a new feature only for serde_json, we just require `alloc` here since as of the moment we don't have a use case of serde without alloc.
serde = ["alloc", "dep:serde", "fuel-asm/serde", "fuel-crypto/serde", "fuel-types/serde", "fuel-merkle/serde", "serde_json", "hashbrown/serde", "bitflags/serde"]
serde = ["alloc", "fuel-asm/serde", "fuel-crypto/serde", "fuel-merkle/serde", "serde_json", "hashbrown/serde", "bitflags/serde"]
40 changes: 25 additions & 15 deletions fuel-tx/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ use crate::{
Transaction,
TxParameters,
TxPointer,
Upgrade,
UpgradePurpose,
Witness,
};

Expand All @@ -44,6 +46,7 @@ use crate::{
transaction::{
CreateBody,
ScriptBody,
UpgradeBody,
},
};
use alloc::{
Expand Down Expand Up @@ -164,6 +167,20 @@ impl TransactionBuilder<Create> {
}
}

impl TransactionBuilder<Upgrade> {
pub fn upgrade(purpose: UpgradePurpose) -> Self {
let tx = Upgrade {
body: UpgradeBody { purpose },
policies: Policies::new().with_max_fee(0),
inputs: Default::default(),
outputs: Default::default(),
witnesses: Default::default(),
metadata: None,
};
Self::with_tx(tx)
}
}

impl TransactionBuilder<Mint> {
pub fn mint(
block_height: BlockHeight,
Expand Down Expand Up @@ -355,8 +372,8 @@ impl<Tx: Buildable> TransactionBuilder<Tx> {
self.add_unsigned_coin_input(
SecretKey::random(&mut rng),
rng.gen(),
rng.gen(),
rng.gen(),
u32::MAX as u64,
*self.params.base_asset_id(),
Default::default(),
)
}
Expand Down Expand Up @@ -477,22 +494,15 @@ impl Finalizable<Mint> for TransactionBuilder<Mint> {
}
}

impl Finalizable<Create> for TransactionBuilder<Create> {
fn finalize(&self) -> Create {
self.finalize_inner()
}

fn finalize_without_signature(&self) -> Create {
self.finalize_without_signature_inner()
}
}

impl Finalizable<Script> for TransactionBuilder<Script> {
fn finalize(&self) -> Script {
impl<Tx> Finalizable<Tx> for TransactionBuilder<Tx>
where
Tx: Buildable,
{
fn finalize(&self) -> Tx {
self.finalize_inner()
}

fn finalize_without_signature(&self) -> Script {
fn finalize_without_signature(&self) -> Tx {
self.finalize_without_signature_inner()
}
}
Expand Down
4 changes: 3 additions & 1 deletion fuel-tx/src/contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,9 @@ impl TryFrom<&Transaction> for Contract {
fn try_from(tx: &Transaction) -> Result<Self, Self::Error> {
match tx {
Transaction::Create(create) => TryFrom::try_from(create),
_ => Err(ValidityError::TransactionScriptOutputContractCreated { index: 0 }),
_ => {
Err(ValidityError::TransactionOutputContainsContractCreated { index: 0 })
}
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions fuel-tx/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,9 @@ mod transaction;
#[cfg(test)]
mod tests;

#[cfg(feature = "test-helpers")]
pub mod test_helper;

#[cfg(feature = "test-helpers")]
pub use builder::{
Buildable,
Expand Down Expand Up @@ -97,6 +100,9 @@ pub use transaction::{
TransactionRepr,
TxId,
TxParameters,
Upgrade,
UpgradeBody,
UpgradePurpose,
UtxoId,
ValidityError,
Witness,
Expand Down
70 changes: 61 additions & 9 deletions fuel-tx/test-helpers/src/lib.rs → fuel-tx/src/test_helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,14 @@ where

#[cfg(feature = "std")]
mod use_std {
use core::marker::PhantomData;
use fuel_crypto::SecretKey;
use fuel_tx::{
use super::{
generate_bytes,
generate_nonempty_padded_bytes,
};
use crate::{
field,
Buildable,
ConsensusParameters,
Contract,
Create,
Finalizable,
Expand All @@ -54,6 +57,13 @@ mod use_std {
Script,
Transaction,
TransactionBuilder,
Upgrade,
UpgradePurpose,
};
use core::marker::PhantomData;
use fuel_crypto::{
Hasher,
SecretKey,
};
use fuel_types::canonical::Deserialize;
use rand::{
Expand All @@ -66,11 +76,7 @@ mod use_std {
Rng,
SeedableRng,
};

use crate::{
generate_bytes,
generate_nonempty_padded_bytes,
};
use strum::EnumCount;

pub struct TransactionFactory<R, Tx>
where
Expand All @@ -87,7 +93,6 @@ mod use_std {
R: Rng + CryptoRng,
{
fn from(rng: R) -> Self {
use strum::EnumCount;
let input_sampler = Uniform::from(0..Input::COUNT);
let output_sampler = Uniform::from(0..Output::COUNT);

Expand Down Expand Up @@ -124,6 +129,7 @@ mod use_std {
Transaction::Script(_) => (),
Transaction::Create(_) => (),
Transaction::Mint(_) => (),
Transaction::Upgrade(_) => (),
})
.unwrap_or(());

Expand Down Expand Up @@ -365,6 +371,41 @@ mod use_std {
}
}

impl<R> TransactionFactory<R, Upgrade>
where
R: Rng + CryptoRng,
{
pub fn transaction(&mut self) -> Upgrade {
self.transaction_with_keys().0
}

pub fn transaction_with_keys(&mut self) -> (Upgrade, Vec<SecretKey>) {
let variant = self.rng.gen_range(0..UpgradePurpose::COUNT);
let consensus_params =
postcard::to_allocvec(&ConsensusParameters::default()).unwrap();
let checksum = Hasher::hash(consensus_params.as_slice());

let purpose = match variant {
0 => UpgradePurpose::StateTransition {
bytecode_hash: self.rng.gen(),
},
1 => UpgradePurpose::ConsensusParameters {
witness_index: 0,
checksum,
},
_ => {
panic!("Not supported")
}
};

let mut builder = TransactionBuilder::<Upgrade>::upgrade(purpose);
builder.add_witness(consensus_params.into());

let keys = self.fill_transaction(&mut builder);
(builder.finalize(), keys)
}
}

impl<R> TransactionFactory<R, Mint>
where
R: Rng + CryptoRng,
Expand Down Expand Up @@ -406,6 +447,17 @@ mod use_std {
}
}

impl<R> Iterator for TransactionFactory<R, Upgrade>
where
R: Rng + CryptoRng,
{
type Item = (Upgrade, Vec<SecretKey>);

fn next(&mut self) -> Option<(Upgrade, Vec<SecretKey>)> {
Some(self.transaction_with_keys())
}
}

impl<R> Iterator for TransactionFactory<R, Mint>
where
R: Rng + CryptoRng,
Expand Down
Loading
Loading