diff --git a/CHANGELOG.md b/CHANGELOG.md index eac583d3518..d57ea13843c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,15 +9,22 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Added - [2135](https://github.com/FuelLabs/fuel-core/pull/2135): Added metrics logging for number of blocks served over the p2p req/res protocol. - [2151](https://github.com/FuelLabs/fuel-core/pull/2151): Added limitations on gas used during dry_run in API. +- [2188](https://github.com/FuelLabs/fuel-core/pull/2188): Added the new variant `V2` for the `ConsensusParameters` which contains the new `block_transaction_size_limit` parameter. - [2163](https://github.com/FuelLabs/fuel-core/pull/2163): Added runnable task for fetching block committer data. ### Changed #### Breaking +- [2199](https://github.com/FuelLabs/fuel-core/pull/2199): Applying several breaking changes to the WASM interface from backlog: + - Get the module to execute WASM byte code from the storage first, an fallback to the built-in version in the case of the `FUEL_ALWAYS_USE_WASM`. + - Added `host_v1` with a new `peek_next_txs_size` method, that accepts `tx_number_limit` and `size_limit`. + - Added new variant of the return type to pass the validation result. It removes block serialization and deserialization and should improve performance. + - Added a V1 execution result type that uses `JSONError` instead of postcard serialized error. It adds flexibility of how variants of the error can be managed. More information about it in https://github.com/FuelLabs/fuel-vm/issues/797. The change also moves `TooManyOutputs` error to the top. It shows that `JSONError` works as expected. - [2145](https://github.com/FuelLabs/fuel-core/pull/2145): feat: Introduce time port in PoA service. - [2155](https://github.com/FuelLabs/fuel-core/pull/2155): Added trait declaration for block committer data - [2142](https://github.com/FuelLabs/fuel-core/pull/2142): Added benchmarks for varied forms of db lookups to assist in optimizations. - [2158](https://github.com/FuelLabs/fuel-core/pull/2158): Log the public address of the signing key, if it is specified +- [2188](https://github.com/FuelLabs/fuel-core/pull/2188): Upgraded the `fuel-vm` to `0.57.0`. More information in the [release](https://github.com/FuelLabs/fuel-vm/releases/tag/v0.57.0). ## [Version 0.35.0] diff --git a/Cargo.lock b/Cargo.lock index e3f3c8b3869..f20a6fe7f1a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3132,7 +3132,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "122c27ab46707017063bf1c6e0b4f3de881e22e81b4059750a0dc95033d9cc26" dependencies = [ "bitflags 2.6.0", - "fuel-types", + "fuel-types 0.56.0", + "serde", + "strum 0.24.1", +] + +[[package]] +name = "fuel-asm" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b29ea55a794c00d0dfaad06f11720a05fa928603f812dca1c38163f2b240860a" +dependencies = [ + "bitflags 2.6.0", + "fuel-types 0.57.0", "serde", "strum 0.24.1", ] @@ -3166,7 +3178,7 @@ dependencies = [ "fuel-core-sync", "fuel-core-trace", "fuel-core-txpool", - "fuel-core-types", + "fuel-core-types 0.35.0", "fuel-core-upgradable-executor", "futures", "hex", @@ -3214,7 +3226,7 @@ dependencies = [ "fuel-core-services", "fuel-core-storage", "fuel-core-sync", - "fuel-core-types", + "fuel-core-types 0.35.0", "futures", "itertools 0.12.1", "num_enum", @@ -3252,7 +3264,7 @@ dependencies = [ "fuel-core-chain-config", "fuel-core-poa", "fuel-core-storage", - "fuel-core-types", + "fuel-core-types 0.35.0", "hex", "humantime", "itertools 0.12.1", @@ -3281,7 +3293,7 @@ dependencies = [ "derivative", "fuel-core-chain-config", "fuel-core-storage", - "fuel-core-types", + "fuel-core-types 0.35.0", "insta", "itertools 0.12.1", "parquet", @@ -3305,7 +3317,7 @@ dependencies = [ "cynic", "derive_more", "eventsource-client", - "fuel-core-types", + "fuel-core-types 0.35.0", "futures", "hex", "hyper-rustls", @@ -3326,7 +3338,7 @@ version = "0.35.0" dependencies = [ "clap 4.5.17", "fuel-core-client", - "fuel-core-types", + "fuel-core-types 0.35.0", "serde_json", "tokio", ] @@ -3339,7 +3351,7 @@ dependencies = [ "fuel-core-chain-config", "fuel-core-poa", "fuel-core-storage", - "fuel-core-types", + "fuel-core-types 0.35.0", "test-case", ] @@ -3351,7 +3363,7 @@ dependencies = [ "derive_more", "fuel-core-storage", "fuel-core-trace", - "fuel-core-types", + "fuel-core-types 0.35.0", ] [[package]] @@ -3363,9 +3375,8 @@ dependencies = [ "fuel-core", "fuel-core-chain-config", "fuel-core-client", - "fuel-core-e2e-client", "fuel-core-trace", - "fuel-core-types", + "fuel-core-types 0.35.0", "futures", "hex", "humantime-serde", @@ -3387,7 +3398,7 @@ dependencies = [ "anyhow", "fuel-core-storage", "fuel-core-trace", - "fuel-core-types", + "fuel-core-types 0.35.0", "hex", "parking_lot", "serde", @@ -3403,7 +3414,7 @@ dependencies = [ "enum-iterator", "fuel-core-services", "fuel-core-storage", - "fuel-core-types", + "fuel-core-types 0.35.0", "fuel-gas-price-algorithm", "futures", "num_enum", @@ -3426,7 +3437,7 @@ dependencies = [ "fuel-core-metrics", "fuel-core-storage", "fuel-core-trace", - "fuel-core-types", + "fuel-core-types 0.35.0", "mockall", "parking_lot", "rayon", @@ -3441,7 +3452,7 @@ version = "0.35.0" dependencies = [ "anyhow", "clap 4.5.17", - "fuel-core-types", + "fuel-core-types 0.35.0", "libp2p-identity", "serde", ] @@ -3484,7 +3495,7 @@ dependencies = [ "fuel-core-services", "fuel-core-storage", "fuel-core-trace", - "fuel-core-types", + "fuel-core-types 0.35.0", "futures", "hex", "ip_network", @@ -3520,7 +3531,7 @@ dependencies = [ "fuel-core-poa", "fuel-core-services", "fuel-core-storage", - "fuel-core-types", + "fuel-core-types 0.35.0", "k256", "mockall", "rand", @@ -3542,7 +3553,7 @@ dependencies = [ "fuel-core-producer", "fuel-core-storage", "fuel-core-trace", - "fuel-core-types", + "fuel-core-types 0.35.0", "mockall", "proptest", "rand", @@ -3567,7 +3578,7 @@ dependencies = [ "fuel-core-services", "fuel-core-storage", "fuel-core-trace", - "fuel-core-types", + "fuel-core-types 0.35.0", "futures", "mockall", "once_cell", @@ -3606,8 +3617,8 @@ dependencies = [ "derive_more", "enum-iterator", "fuel-core-storage", - "fuel-core-types", - "fuel-vm", + "fuel-core-types 0.35.0", + "fuel-vm 0.57.0", "impl-tools", "itertools 0.12.1", "mockall", @@ -3630,7 +3641,7 @@ dependencies = [ "async-trait", "fuel-core-services", "fuel-core-trace", - "fuel-core-types", + "fuel-core-types 0.35.0", "futures", "mockall", "rand", @@ -3664,7 +3675,7 @@ dependencies = [ "fuel-core-storage", "fuel-core-trace", "fuel-core-txpool", - "fuel-core-types", + "fuel-core-types 0.35.0", "fuel-core-upgradable-executor", "futures", "hex", @@ -3709,7 +3720,7 @@ dependencies = [ "fuel-core-storage", "fuel-core-trace", "fuel-core-txpool", - "fuel-core-types", + "fuel-core-types 0.35.0", "itertools 0.12.1", "mockall", "num-rational", @@ -3731,7 +3742,7 @@ dependencies = [ "bs58", "derivative", "derive_more", - "fuel-vm", + "fuel-vm 0.57.0", "rand", "secrecy", "serde", @@ -3739,6 +3750,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "fuel-core-types" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84fda0c6dc7b3bd24a993b3902f55862b8db0fa6de5b0f1d45f5942bc59792eb" +dependencies = [ + "anyhow", + "derivative", + "derive_more", + "fuel-vm 0.56.0", + "secrecy", + "serde", + "tai64", + "zeroize", +] + [[package]] name = "fuel-core-upgradable-executor" version = "0.35.0" @@ -3747,7 +3774,7 @@ dependencies = [ "derive_more", "fuel-core-executor", "fuel-core-storage", - "fuel-core-types", + "fuel-core-types 0.35.0", "fuel-core-wasm-executor", "ntest", "parking_lot", @@ -3763,10 +3790,12 @@ dependencies = [ "anyhow", "fuel-core-executor", "fuel-core-storage", - "fuel-core-types", + "fuel-core-types 0.35.0", + "fuel-core-types 0.35.0 (registry+https://github.com/rust-lang/crates.io-index)", "postcard", "proptest", "serde", + "serde_json", ] [[package]] @@ -3774,12 +3803,28 @@ name = "fuel-crypto" version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33548590131674e8f272a3e056be4dbaa1de7cb364eab2b17987cd5c0dc31cb0" +dependencies = [ + "ecdsa", + "ed25519-dalek", + "fuel-types 0.56.0", + "k256", + "p256", + "serde", + "sha2 0.10.8", + "zeroize", +] + +[[package]] +name = "fuel-crypto" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2661b2a6c43e811be4892250513a6f4c46a69cc7092a1e5b240f49697f08292e" dependencies = [ "coins-bip32", "coins-bip39", "ecdsa", "ed25519-dalek", - "fuel-types", + "fuel-types 0.57.0", "k256", "lazy_static", "p256", @@ -3802,6 +3847,18 @@ dependencies = [ "synstructure", ] +[[package]] +name = "fuel-derive" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03509567813a351ca60d8507b2ac476b06c1590f2e9edbe72bc205bb04e0af12" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.77", + "synstructure", +] + [[package]] name = "fuel-gas-price-algorithm" version = "0.35.0" @@ -3820,7 +3877,22 @@ checksum = "cf17ce8ee5e8b573ea584c223635ff09f1288ad022bcf662954fdccb907602eb" dependencies = [ "derive_more", "digest 0.10.7", - "fuel-storage", + "fuel-storage 0.56.0", + "hashbrown 0.13.2", + "hex", + "serde", + "sha2 0.10.8", +] + +[[package]] +name = "fuel-merkle" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24938ee8a5e9efe71994203527dffb4c81872aa2953de0c347ad38696527b58a" +dependencies = [ + "derive_more", + "digest 0.10.7", + "fuel-storage 0.57.0", "hashbrown 0.13.2", "hex", "serde", @@ -3833,6 +3905,12 @@ version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c1b711f28553ddc5f3546711bd220e144ce4c1af7d9e9a1f70b2f20d9f5b791" +[[package]] +name = "fuel-storage" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4283f9cabc26a1154a31268e79de1e0f317d57231b4dc8d7282efb22e49d2ed3" + [[package]] name = "fuel-tx" version = "0.56.0" @@ -3842,10 +3920,32 @@ dependencies = [ "bitflags 2.6.0", "derivative", "derive_more", - "fuel-asm", - "fuel-crypto", - "fuel-merkle", - "fuel-types", + "fuel-asm 0.56.0", + "fuel-crypto 0.56.0", + "fuel-merkle 0.56.0", + "fuel-types 0.56.0", + "hashbrown 0.14.5", + "itertools 0.10.5", + "postcard", + "serde", + "serde_json", + "strum 0.24.1", + "strum_macros 0.24.3", +] + +[[package]] +name = "fuel-tx" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572f9e8fdda6abfe83cf1456a11eabf1de66d682176fb097f2f950704cc50c26" +dependencies = [ + "bitflags 2.6.0", + "derivative", + "derive_more", + "fuel-asm 0.57.0", + "fuel-crypto 0.57.0", + "fuel-merkle 0.57.0", + "fuel-types 0.57.0", "hashbrown 0.14.5", "itertools 0.10.5", "postcard", @@ -3862,7 +3962,18 @@ version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b6fb26bcb408b6897e603f68cf60bbbaf6d15381c99f54a69ea743a58235ac1" dependencies = [ - "fuel-derive", + "fuel-derive 0.56.0", + "hex", + "serde", +] + +[[package]] +name = "fuel-types" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f196060a10db0293cdfca455f7e2f3a7914f46f25e0fbc2d28cf0a11e835a86" +dependencies = [ + "fuel-derive 0.57.0", "hex", "rand", "serde", @@ -3873,6 +3984,37 @@ name = "fuel-vm" version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64fc4695efac9207276f6229f2dd9811848b328a13604a698f7bce1d452bd986" +dependencies = [ + "async-trait", + "backtrace", + "bitflags 2.6.0", + "derivative", + "derive_more", + "ethnum", + "fuel-asm 0.56.0", + "fuel-crypto 0.56.0", + "fuel-merkle 0.56.0", + "fuel-storage 0.56.0", + "fuel-tx 0.56.0", + "fuel-types 0.56.0", + "hashbrown 0.14.5", + "itertools 0.10.5", + "libm", + "paste", + "percent-encoding", + "primitive-types", + "serde", + "serde_with", + "sha3", + "static_assertions", + "strum 0.24.1", +] + +[[package]] +name = "fuel-vm" +version = "0.57.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f4e0cc4ae65d00df6f3dcae90b81dd21135b45b932a79e368f35d255df12a1" dependencies = [ "anyhow", "async-trait", @@ -3881,12 +4023,12 @@ dependencies = [ "derivative", "derive_more", "ethnum", - "fuel-asm", - "fuel-crypto", - "fuel-merkle", - "fuel-storage", - "fuel-tx", - "fuel-types", + "fuel-asm 0.57.0", + "fuel-crypto 0.57.0", + "fuel-merkle 0.57.0", + "fuel-storage 0.57.0", + "fuel-tx 0.57.0", + "fuel-types 0.57.0", "hashbrown 0.14.5", "itertools 0.10.5", "libm", @@ -4581,7 +4723,7 @@ dependencies = [ "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "windows-core 0.52.0", + "windows-core", ] [[package]] @@ -7820,9 +7962,9 @@ dependencies = [ [[package]] name = "secp256k1" -version = "0.26.0" +version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4124a35fe33ae14259c490fd70fa199a32b9ce9502f2ee6bc4f81ec06fa65894" +checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ "rand", "secp256k1-sys", @@ -7830,9 +7972,9 @@ dependencies = [ [[package]] name = "secp256k1-sys" -version = "0.8.1" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +checksum = "d4387882333d3aa8cb20530a17c69a3752e97837832f34f6dccc760e715001d9" dependencies = [ "cc", ] @@ -8615,7 +8757,7 @@ dependencies = [ "fuel-core-storage", "fuel-core-trace", "fuel-core-txpool", - "fuel-core-types", + "fuel-core-types 0.35.0", "futures", "itertools 0.12.1", "rand", @@ -9707,7 +9849,7 @@ version = "0.51.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca229916c5ee38c2f2bc1e9d8f04df975b4bd93f9955dc69fabb5d91270045c9" dependencies = [ - "windows-core 0.51.1", + "windows-core", "windows-targets 0.48.5", ] @@ -9720,15 +9862,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows-core" -version = "0.52.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-sys" version = "0.48.0" diff --git a/Cargo.toml b/Cargo.toml index 22acb83d586..06ec3a46d43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,7 @@ fuel-core-xtask = { version = "0.0.0", path = "./xtask" } fuel-gas-price-algorithm = { version = "0.35.0", path = "crates/fuel-gas-price-algorithm" } # Fuel dependencies -fuel-vm-private = { version = "0.56.0", package = "fuel-vm", default-features = false } +fuel-vm-private = { version = "0.57.0", package = "fuel-vm", default-features = false } # Common dependencies anyhow = "1.0" @@ -112,7 +112,7 @@ postcard = "1.0" tracing-attributes = "0.1" tracing-subscriber = "0.3" serde = "1.0" -serde_json = "1.0" +serde_json = { version = "1.0", default-features = false } serde_with = { version = "3.4", default-features = false } strum = { version = "0.25" } strum_macros = "0.25" diff --git a/bin/e2e-test-client/Cargo.toml b/bin/e2e-test-client/Cargo.toml index b187c79d4bc..fc9241fa8df 100644 --- a/bin/e2e-test-client/Cargo.toml +++ b/bin/e2e-test-client/Cargo.toml @@ -14,7 +14,6 @@ publish = true [dependencies] anyhow = { workspace = true } -fuel-core = { workspace = true, default-features = false, optional = true } fuel-core-chain-config = { workspace = true, features = ["default"] } fuel-core-client = { workspace = true } fuel-core-types = { workspace = true, features = ["test-helpers"] } @@ -31,14 +30,15 @@ toml = { version = "0.5" } [dev-dependencies] assert_cmd = "2.0" -fuel-core-e2e-client = { path = ".", features = [ - "dev-deps", -], default-features = false } +fuel-core = { workspace = true, features = [ + "rocksdb", + "wasm-executor", + "p2p", + "test-helpers", +] } fuel-core-trace = { path = "../../crates/trace" } insta = { workspace = true } tempfile = { workspace = true } [features] -default = ["fuel-core?/default"] -p2p = ["fuel-core?/p2p"] -dev-deps = ["fuel-core/test-helpers"] +default = [] diff --git a/bin/e2e-test-client/src/tests/script.rs b/bin/e2e-test-client/src/tests/script.rs index db65ee6cb6f..a14268627e0 100644 --- a/bin/e2e-test-client/src/tests/script.rs +++ b/bin/e2e-test-client/src/tests/script.rs @@ -78,7 +78,7 @@ pub async fn dry_run(ctx: &TestContext) -> Result<(), Failed> { ) .await??; - _dry_runs(ctx, &[transaction], 1000, DryRunResult::Successful).await + _dry_runs(ctx, &[transaction], 100, DryRunResult::Successful).await } // Dry run multiple transactions @@ -97,7 +97,7 @@ pub async fn dry_run_multiple_txs(ctx: &TestContext) -> Result<(), Failed> { _dry_runs( ctx, &[transaction1, transaction2], - 1000, + 100, DryRunResult::Successful, ) .await @@ -140,7 +140,7 @@ pub async fn run_contract_large_state(ctx: &TestContext) -> Result<(), Failed> { timeout(Duration::from_secs(20), deployment_request).await??; } - _dry_runs(ctx, &[dry_run], 1000, DryRunResult::MayFail).await + _dry_runs(ctx, &[dry_run], 100, DryRunResult::MayFail).await } pub async fn arbitrary_transaction(ctx: &TestContext) -> Result<(), Failed> { @@ -172,7 +172,7 @@ pub async fn arbitrary_transaction(ctx: &TestContext) -> Result<(), Failed> { assert_eq!(dry_run_tx_from_raw, dry_run_tx_from_json); - _dry_runs(ctx, &[dry_run_tx_from_json], 1000, DryRunResult::MayFail).await + _dry_runs(ctx, &[dry_run_tx_from_json], 100, DryRunResult::MayFail).await } async fn _dry_runs( diff --git a/bin/e2e-test-client/tests/integration_tests.rs b/bin/e2e-test-client/tests/integration_tests.rs index f854bbd2030..b325ee32763 100644 --- a/bin/e2e-test-client/tests/integration_tests.rs +++ b/bin/e2e-test-client/tests/integration_tests.rs @@ -31,7 +31,6 @@ async fn works_in_local_env() { } // Spins up a node for each wallet and verifies that the suite works across multiple nodes -#[cfg(feature = "p2p")] #[tokio::test(flavor = "multi_thread")] async fn works_in_multinode_local_env() { use fuel_core::p2p_test_helpers::*; @@ -120,6 +119,8 @@ fn dev_config() -> Config { .consensus_parameters .set_tx_params(tx_parameters); chain_config.consensus_parameters.set_fee_params(fee_params); + chain_config.state_transition_bytecode = + fuel_core::upgradable_executor::WASM_BYTECODE.to_vec(); let reader = reader.with_chain_config(chain_config); let mut config = Config::local_node_with_reader(reader); diff --git a/bin/fuel-core/chainspec/local-testnet/chain_config.json b/bin/fuel-core/chainspec/local-testnet/chain_config.json index cf5ff3a1bbe..3c2027e824f 100644 --- a/bin/fuel-core/chainspec/local-testnet/chain_config.json +++ b/bin/fuel-core/chainspec/local-testnet/chain_config.json @@ -1,7 +1,7 @@ { "chain_name": "Local testnet", "consensus_parameters": { - "V1": { + "V2": { "tx_params": { "V1": { "max_inputs": 255, @@ -293,6 +293,7 @@ }, "base_asset_id": "f8f8b6283d7fa5b672b530cbb84fcccb4ff8dc40f8176ef4544ddb1f1952ad07", "block_gas_limit": 30000000, + "block_transaction_size_limit": 129024, "privileged_address": "9f0e19d6c2a6283a3222426ab2630d35516b1799b503f37b02105bebe1b8a3e9" } }, diff --git a/bin/fuel-core/chainspec/local-testnet/state_transition_bytecode.wasm b/bin/fuel-core/chainspec/local-testnet/state_transition_bytecode.wasm index 5a485c43b5c..68cd526f472 100755 Binary files a/bin/fuel-core/chainspec/local-testnet/state_transition_bytecode.wasm and b/bin/fuel-core/chainspec/local-testnet/state_transition_bytecode.wasm differ diff --git a/bin/fuel-core/src/cli.rs b/bin/fuel-core/src/cli.rs index 2abb225bb66..00a81bfe5ae 100644 --- a/bin/fuel-core/src/cli.rs +++ b/bin/fuel-core/src/cli.rs @@ -1,5 +1,8 @@ use clap::Parser; -use fuel_core::ShutdownListener; +use fuel_core::{ + upgradable_executor, + ShutdownListener, +}; use fuel_core_chain_config::{ ChainConfig, SnapshotReader, @@ -148,11 +151,10 @@ pub async fn run_cli() -> anyhow::Result<()> { pub fn local_testnet_chain_config() -> ChainConfig { const TESTNET_CHAIN_CONFIG: &[u8] = include_bytes!("../chainspec/local-testnet/chain_config.json"); - const TESTNET_CHAIN_CONFIG_STATE_BYTECODE: &[u8] = - include_bytes!("../chainspec/local-testnet/state_transition_bytecode.wasm"); let mut config: ChainConfig = serde_json::from_slice(TESTNET_CHAIN_CONFIG).unwrap(); - config.state_transition_bytecode = TESTNET_CHAIN_CONFIG_STATE_BYTECODE.to_vec(); + config.state_transition_bytecode = upgradable_executor::WASM_BYTECODE.to_vec(); + config } diff --git a/crates/chain-config/src/config/snapshots/fuel_core_chain_config__config__chain__tests__snapshot_local_testnet_config.snap b/crates/chain-config/src/config/snapshots/fuel_core_chain_config__config__chain__tests__snapshot_local_testnet_config.snap index 4e34fcc3a5f..c3c1a5bf206 100644 --- a/crates/chain-config/src/config/snapshots/fuel_core_chain_config__config__chain__tests__snapshot_local_testnet_config.snap +++ b/crates/chain-config/src/config/snapshots/fuel_core_chain_config__config__chain__tests__snapshot_local_testnet_config.snap @@ -5,7 +5,7 @@ expression: json { "chain_name": "local_testnet", "consensus_parameters": { - "V1": { + "V2": { "tx_params": { "V1": { "max_inputs": 255, @@ -297,6 +297,7 @@ expression: json }, "base_asset_id": "0000000000000000000000000000000000000000000000000000000000000000", "block_gas_limit": 100000000, + "block_transaction_size_limit": 129024, "privileged_address": "0000000000000000000000000000000000000000000000000000000000000000" } }, diff --git a/crates/client/assets/schema.sdl b/crates/client/assets/schema.sdl index 8929f76b0ef..c7692a11adb 100644 --- a/crates/client/assets/schema.sdl +++ b/crates/client/assets/schema.sdl @@ -198,6 +198,7 @@ type ConsensusParameters { feeParams: FeeParameters! baseAssetId: AssetId! blockGasLimit: U64! + blockTransactionSizeLimit: U64! chainId: U64! gasCosts: GasCosts! privilegedAddress: Address! diff --git a/crates/client/src/client/schema/chain.rs b/crates/client/src/client/schema/chain.rs index 7cafc355543..7f76de69d16 100644 --- a/crates/client/src/client/schema/chain.rs +++ b/crates/client/src/client/schema/chain.rs @@ -20,6 +20,7 @@ pub struct ConsensusParameters { pub fee_params: FeeParameters, pub base_asset_id: AssetId, pub block_gas_limit: U64, + pub block_transaction_size_limit: U64, pub chain_id: U64, pub gas_costs: GasCosts, pub privileged_address: Address, @@ -479,7 +480,7 @@ impl TryFrom for fuel_core_types::fuel_tx::ConsensusParamet fn try_from(params: ConsensusParameters) -> Result { match params.version { ConsensusParametersVersion::V1 => Ok( - fuel_core_types::fuel_tx::consensus_parameters::ConsensusParametersV1 { + fuel_core_types::fuel_tx::consensus_parameters::ConsensusParametersV2 { tx_params: params.tx_params.try_into()?, predicate_params: params.predicate_params.try_into()?, script_params: params.script_params.try_into()?, @@ -487,6 +488,9 @@ impl TryFrom for fuel_core_types::fuel_tx::ConsensusParamet fee_params: params.fee_params.try_into()?, base_asset_id: params.base_asset_id.into(), block_gas_limit: params.block_gas_limit.into(), + block_transaction_size_limit: params + .block_transaction_size_limit + .into(), chain_id: params.chain_id.0.into(), gas_costs: params.gas_costs.try_into()?, privileged_address: params.privileged_address.into(), diff --git a/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__chain__tests__chain_gql_query_output.snap b/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__chain__tests__chain_gql_query_output.snap index 50746c31bd6..276475d619e 100644 --- a/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__chain__tests__chain_gql_query_output.snap +++ b/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__chain__tests__chain_gql_query_output.snap @@ -75,6 +75,7 @@ query { } baseAssetId blockGasLimit + blockTransactionSizeLimit chainId gasCosts { version diff --git a/crates/fuel-core/Cargo.toml b/crates/fuel-core/Cargo.toml index f1bfab1c31b..7032d1164ff 100644 --- a/crates/fuel-core/Cargo.toml +++ b/crates/fuel-core/Cargo.toml @@ -44,7 +44,7 @@ hyper = { workspace = true } indicatif = { workspace = true, default-features = true } itertools = { workspace = true } num_cpus = { version = "1.16.0", optional = true } -postcard = { workspace = true } +postcard = { workspace = true, optional = true } rand = { workspace = true } rocksdb = { version = "0.21", default-features = false, features = [ "lz4", @@ -89,7 +89,7 @@ smt = [ ] p2p = ["dep:fuel-core-p2p", "dep:fuel-core-sync"] relayer = ["dep:fuel-core-relayer"] -rocksdb = ["dep:rocksdb", "dep:tempfile", "dep:num_cpus"] +rocksdb = ["dep:rocksdb", "dep:tempfile", "dep:num_cpus", "dep:postcard"] test-helpers = [ "fuel-core-database/test-helpers", "fuel-core-p2p?/test-helpers", diff --git a/crates/fuel-core/src/lib.rs b/crates/fuel-core/src/lib.rs index f78b69ff45e..40d866a137d 100644 --- a/crates/fuel-core/src/lib.rs +++ b/crates/fuel-core/src/lib.rs @@ -25,6 +25,8 @@ pub use fuel_core_sync as sync; pub use fuel_core_txpool as txpool; #[doc(no_inline)] pub use fuel_core_types as types; +#[doc(no_inline)] +pub use fuel_core_upgradable_executor as upgradable_executor; pub mod coins_query; pub mod combined_database; diff --git a/crates/fuel-core/src/query/message/test.rs b/crates/fuel-core/src/query/message/test.rs index 9e95db644d6..258de7fc7be 100644 --- a/crates/fuel-core/src/query/message/test.rs +++ b/crates/fuel-core/src/query/message/test.rs @@ -1,5 +1,6 @@ use std::ops::Deref; +use fuel_core_txpool::types::ContractId; use fuel_core_types::{ blockchain::header::{ ApplicationHeader, @@ -8,13 +9,11 @@ use fuel_core_types::{ }, entities::relayer::message::MerkleProof, fuel_tx::{ + AssetId, Script, Transaction, }, - fuel_types::{ - BlockHeight, - *, - }, + fuel_types::BlockHeight, tai64::Tai64, }; diff --git a/crates/fuel-core/src/schema/chain.rs b/crates/fuel-core/src/schema/chain.rs index 0ff014b3b96..16ec77b1e46 100644 --- a/crates/fuel-core/src/schema/chain.rs +++ b/crates/fuel-core/src/schema/chain.rs @@ -117,64 +117,54 @@ impl From for DependentCost { impl ConsensusParameters { async fn version(&self) -> ConsensusParametersVersion { match self.0.as_ref() { - fuel_tx::ConsensusParameters::V1(_) => ConsensusParametersVersion::V1, + fuel_tx::ConsensusParameters::V1(_) | fuel_tx::ConsensusParameters::V2(_) => { + ConsensusParametersVersion::V1 + } } } - #[graphql(complexity = "QUERY_COSTS.storage_read + child_complexity")] async fn tx_params(&self) -> TxParameters { TxParameters(self.0.tx_params().to_owned()) } - #[graphql(complexity = "QUERY_COSTS.storage_read + child_complexity")] async fn predicate_params(&self) -> PredicateParameters { PredicateParameters(self.0.predicate_params().to_owned()) } - #[graphql(complexity = "QUERY_COSTS.storage_read + child_complexity")] async fn script_params(&self) -> ScriptParameters { ScriptParameters(self.0.script_params().to_owned()) } - #[graphql(complexity = "QUERY_COSTS.storage_read + child_complexity")] async fn contract_params(&self) -> ContractParameters { ContractParameters(self.0.contract_params().to_owned()) } - #[graphql(complexity = "QUERY_COSTS.storage_read + child_complexity")] async fn fee_params(&self) -> FeeParameters { FeeParameters(self.0.fee_params().to_owned()) } - #[graphql(complexity = "QUERY_COSTS.storage_read")] async fn base_asset_id(&self) -> AssetId { AssetId(*self.0.base_asset_id()) } - #[graphql(complexity = "QUERY_COSTS.storage_read")] async fn block_gas_limit(&self) -> U64 { self.0.block_gas_limit().into() } + async fn block_transaction_size_limit(&self) -> U64 { + self.0.block_transaction_size_limit().into() + } + async fn chain_id(&self) -> U64 { (*self.0.chain_id()).into() } - #[graphql(complexity = "QUERY_COSTS.storage_read + child_complexity")] async fn gas_costs(&self) -> async_graphql::Result { Ok(GasCosts(self.0.gas_costs().clone())) } - #[graphql(complexity = "QUERY_COSTS.storage_read")] - async fn privileged_address( - &self, - ctx: &Context<'_>, - ) -> async_graphql::Result
{ - let params = ctx - .data_unchecked::() - .latest_consensus_params(); - - Ok(Address(*params.privileged_address())) + async fn privileged_address(&self) -> async_graphql::Result
{ + Ok(Address(*self.0.privileged_address())) } } diff --git a/crates/fuel-core/src/schema/tx/input.rs b/crates/fuel-core/src/schema/tx/input.rs index 226526b888b..5245a346212 100644 --- a/crates/fuel-core/src/schema/tx/input.rs +++ b/crates/fuel-core/src/schema/tx/input.rs @@ -196,7 +196,7 @@ impl From<&fuel_tx::Input> for Input { tx_pointer: TxPointer(*tx_pointer), witness_index: Default::default(), predicate_gas_used: (*predicate_gas_used).into(), - predicate: HexString(predicate.clone()), + predicate: HexString(predicate.to_vec()), predicate_data: HexString(predicate_data.clone()), }), fuel_tx::Input::Contract(contract) => Input::Contract(contract.into()), @@ -239,7 +239,7 @@ impl From<&fuel_tx::Input> for Input { witness_index: Default::default(), predicate_gas_used: (*predicate_gas_used).into(), data: HexString(Default::default()), - predicate: HexString(predicate.clone()), + predicate: HexString(predicate.to_vec()), predicate_data: HexString(predicate_data.clone()), }), fuel_tx::Input::MessageDataSigned( @@ -283,7 +283,7 @@ impl From<&fuel_tx::Input> for Input { witness_index: Default::default(), predicate_gas_used: (*predicate_gas_used).into(), data: HexString(data.clone()), - predicate: HexString(predicate.clone()), + predicate: HexString(predicate.to_vec()), predicate_data: HexString(predicate_data.clone()), }), } diff --git a/crates/fuel-core/src/service.rs b/crates/fuel-core/src/service.rs index 43a6be09049..4894a55f699 100644 --- a/crates/fuel-core/src/service.rs +++ b/crates/fuel-core/src/service.rs @@ -401,6 +401,7 @@ impl RunnableService for Task { _: Self::TaskParams, ) -> anyhow::Result { let mut watcher = watcher.clone(); + for service in self.services.iter() { tokio::select! { _ = watcher.wait_stopping_or_stopped() => { diff --git a/crates/fuel-core/src/service/adapters.rs b/crates/fuel-core/src/service/adapters.rs index e56320e75c5..7c356611967 100644 --- a/crates/fuel-core/src/service/adapters.rs +++ b/crates/fuel-core/src/service/adapters.rs @@ -2,12 +2,14 @@ use fuel_core_consensus_module::{ block_verifier::Verifier, RelayerConsensusConfig, }; +use fuel_core_executor::executor::OnceTransactionsSource; use fuel_core_importer::ImporterResult; use fuel_core_poa::{ ports::BlockSigner, signer::SignMode, }; use fuel_core_services::stream::BoxStream; +use fuel_core_storage::transactional::Changes; #[cfg(feature = "p2p")] use fuel_core_types::services::p2p::peer_reputation::AppScore; use fuel_core_types::{ @@ -15,8 +17,16 @@ use fuel_core_types::{ block::Block, consensus::Consensus, }, + fuel_tx::Transaction, fuel_types::BlockHeight, - services::block_importer::SharedImportResult, + services::{ + block_importer::SharedImportResult, + block_producer::Components, + executor::{ + Result as ExecutorResult, + UncommittedResult, + }, + }, tai64::Tai64, }; use fuel_core_upgradable_executor::executor::Executor; @@ -108,7 +118,7 @@ impl TransactionsSource { #[derive(Clone)] pub struct ExecutorAdapter { - pub executor: Arc>>, + pub(crate) executor: Arc>>, } impl ExecutorAdapter { @@ -122,6 +132,23 @@ impl ExecutorAdapter { executor: Arc::new(executor), } } + + pub fn produce_without_commit_from_vector( + &self, + component: Components>, + ) -> ExecutorResult> { + let new_components = Components { + header_to_produce: component.header_to_produce, + transactions_source: OnceTransactionsSource::new( + component.transactions_source, + ), + gas_price: component.gas_price, + coinbase_recipient: component.coinbase_recipient, + }; + + self.executor + .produce_without_commit_with_source(new_components) + } } #[derive(Clone)] diff --git a/crates/fuel-core/src/service/adapters/executor.rs b/crates/fuel-core/src/service/adapters/executor.rs index 787e0db6558..b7663a0d90e 100644 --- a/crates/fuel-core/src/service/adapters/executor.rs +++ b/crates/fuel-core/src/service/adapters/executor.rs @@ -9,7 +9,9 @@ use fuel_core_types::{ }; impl fuel_core_executor::ports::TransactionsSource for TransactionsSource { - fn next(&self, gas_limit: u64) -> Vec { + // TODO: Use `tx_count_limit` https://github.com/FuelLabs/fuel-core/issues/2114 + // TODO: Use `size_limit` https://github.com/FuelLabs/fuel-core/issues/2133 + fn next(&self, gas_limit: u64, _: u16, _: u32) -> Vec { self.txpool .select_transactions(gas_limit) .into_iter() diff --git a/crates/fuel-core/src/service/adapters/producer.rs b/crates/fuel-core/src/service/adapters/producer.rs index 3490027406f..0449de9e841 100644 --- a/crates/fuel-core/src/service/adapters/producer.rs +++ b/crates/fuel-core/src/service/adapters/producer.rs @@ -13,7 +13,6 @@ use crate::{ sub_services::BlockProducerService, }, }; -use fuel_core_executor::executor::OnceTransactionsSource; use fuel_core_producer::{ block_producer::gas_price::{ ConsensusParametersProvider as ConsensusParametersProviderTrait, @@ -99,17 +98,7 @@ impl fuel_core_producer::ports::BlockProducer> for ExecutorAdap &self, component: Components>, ) -> ExecutorResult> { - let new_components = Components { - header_to_produce: component.header_to_produce, - transactions_source: OnceTransactionsSource::new( - component.transactions_source, - ), - gas_price: component.gas_price, - coinbase_recipient: component.coinbase_recipient, - }; - - self.executor - .produce_without_commit_with_source(new_components) + self.produce_without_commit_from_vector(component) } } diff --git a/crates/services/consensus_module/poa/src/service_test.rs b/crates/services/consensus_module/poa/src/service_test.rs index ac22ff286bd..6b04e339a2b 100644 --- a/crates/services/consensus_module/poa/src/service_test.rs +++ b/crates/services/consensus_module/poa/src/service_test.rs @@ -482,6 +482,7 @@ fn test_signing_key() -> Secret { } #[derive(Debug, PartialEq)] +#[allow(clippy::large_enum_variant)] enum FakeProducedBlock { Predefined(Block), New(BlockHeight, Tai64), diff --git a/crates/services/executor/Cargo.toml b/crates/services/executor/Cargo.toml index ca849cbff13..9f3627f07d1 100644 --- a/crates/services/executor/Cargo.toml +++ b/crates/services/executor/Cargo.toml @@ -11,7 +11,9 @@ description = "Fuel Block Executor" [dependencies] anyhow = { workspace = true } -fuel-core-storage = { workspace = true, features = ["alloc"] } +fuel-core-storage = { workspace = true, default-features = false, features = [ + "alloc", +] } fuel-core-types = { workspace = true, default-features = false, features = [ "alloc", ] } diff --git a/crates/services/executor/src/executor.rs b/crates/services/executor/src/executor.rs index b54302ee7c6..f5e8be5886a 100644 --- a/crates/services/executor/src/executor.rs +++ b/crates/services/executor/src/executor.rs @@ -186,7 +186,7 @@ impl OnceTransactionsSource { } impl TransactionsSource for OnceTransactionsSource { - fn next(&self, _: u64) -> Vec { + fn next(&self, _: u64, _: u16, _: u32) -> Vec { let mut lock = self.transactions.lock(); core::mem::take(lock.as_mut()) } @@ -565,9 +565,13 @@ where let block_gas_limit = self.consensus_params.block_gas_limit(); let mut remaining_gas_limit = block_gas_limit.saturating_sub(data.used_gas); + // TODO: Handle `remaining_tx_count` https://github.com/FuelLabs/fuel-core/issues/2114 + let remaining_tx_count = u16::MAX; + // TODO: Handle `remaining_size` https://github.com/FuelLabs/fuel-core/issues/2133 + let remaining_size = u32::MAX; let mut regular_tx_iter = l2_tx_source - .next(remaining_gas_limit) + .next(remaining_gas_limit, remaining_tx_count, remaining_size) .into_iter() .peekable(); while regular_tx_iter.peek().is_some() { @@ -596,7 +600,7 @@ where } regular_tx_iter = l2_tx_source - .next(remaining_gas_limit) + .next(remaining_gas_limit, remaining_tx_count, remaining_size) .into_iter() .peekable(); } @@ -796,6 +800,14 @@ where if new_tx != old_tx { let chain_id = self.consensus_params.chain_id(); let transaction_id = old_tx.id(&chain_id); + + tracing::info!( + "Transaction {:?} does not match: new_tx {:?} and old_tx {:?}", + transaction_id, + new_tx, + old_tx + ); + Err(ExecutorError::InvalidTransactionOutcome { transaction_id }) } else { Ok(()) @@ -806,6 +818,12 @@ where .generate(&message_ids[..], *event_inbox_root) .map_err(ExecutorError::BlockHeaderError)?; if new_block.header() != old_block.header() { + tracing::info!( + "Headers does not match: new_block {:?} and old_block {:?}", + new_block, + old_block + ); + Err(ExecutorError::BlockMismatch) } else { Ok(()) diff --git a/crates/services/executor/src/ports.rs b/crates/services/executor/src/ports.rs index 8bf3b606d7d..d4f02a7530a 100644 --- a/crates/services/executor/src/ports.rs +++ b/crates/services/executor/src/ports.rs @@ -29,6 +29,7 @@ use alloc::{ }; /// The wrapper around either `Transaction` or `CheckedTransaction`. +#[allow(clippy::large_enum_variant)] pub enum MaybeCheckedTransaction { CheckedTransaction(CheckedTransaction, ConsensusParametersVersion), Transaction(fuel_tx::Transaction), @@ -115,7 +116,12 @@ impl TransactionExt for MaybeCheckedTransaction { pub trait TransactionsSource { /// Returns the next batch of transactions to satisfy the `gas_limit`. - fn next(&self, gas_limit: u64) -> Vec; + fn next( + &self, + gas_limit: u64, + tx_count_limit: u16, + size_limit: u32, + ) -> Vec; } pub trait RelayerPort { diff --git a/crates/services/upgradable-executor/Cargo.toml b/crates/services/upgradable-executor/Cargo.toml index a58e694c1b0..4b340df0a25 100644 --- a/crates/services/upgradable-executor/Cargo.toml +++ b/crates/services/upgradable-executor/Cargo.toml @@ -16,7 +16,9 @@ derive_more = { workspace = true, optional = true } fuel-core-executor = { workspace = true } fuel-core-storage = { workspace = true, features = ["std"] } fuel-core-types = { workspace = true, features = ["std"] } -fuel-core-wasm-executor = { workspace = true, optional = true } +fuel-core-wasm-executor = { workspace = true, features = [ + "std", +], optional = true } parking_lot = { workspace = true, optional = true } postcard = { workspace = true, optional = true } tracing = { workspace = true, optional = true } diff --git a/crates/services/upgradable-executor/src/executor.rs b/crates/services/upgradable-executor/src/executor.rs index 4a654a480a2..bacdb201b50 100644 --- a/crates/services/upgradable-executor/src/executor.rs +++ b/crates/services/upgradable-executor/src/executor.rs @@ -63,6 +63,12 @@ use fuel_core_storage::{ use fuel_core_types::blockchain::block::PartialFuelBlock; #[cfg(any(test, feature = "test-helpers"))] use fuel_core_types::services::executor::UncommittedResult; +#[cfg(feature = "wasm-executor")] +use fuel_core_wasm_executor::utils::{ + convert_from_v0_execution_result, + convert_from_v1_execution_result, + ReturnType, +}; #[cfg(feature = "wasm-executor")] enum ExecutionStrategy { @@ -89,10 +95,7 @@ pub struct Executor { execution_strategy: ExecutionStrategy, #[cfg(feature = "wasm-executor")] cached_modules: parking_lot::Mutex< - std::collections::HashMap< - fuel_core_types::blockchain::header::StateTransitionBytecodeVersion, - wasmtime::Module, - >, + std::collections::HashMap, >, } @@ -383,7 +386,12 @@ where self.native_produce_inner(block, options, dry_run) } ExecutionStrategy::Wasm { module } => { - self.wasm_produce_inner(module, block, options, dry_run) + let maybe_blocks_module = self.get_module(block_version).ok(); + if let Some(blocks_module) = maybe_blocks_module { + self.wasm_produce_inner(&blocks_module, block, options, dry_run) + } else { + self.wasm_produce_inner(module, block, options, dry_run) + } } } } else { @@ -426,7 +434,12 @@ where match &self.execution_strategy { ExecutionStrategy::Native => self.native_validate_inner(block, options), ExecutionStrategy::Wasm { module } => { - self.wasm_validate_inner(module, block, options) + let maybe_blocks_module = self.get_module(block_version).ok(); + if let Some(blocks_module) = maybe_blocks_module { + self.wasm_validate_inner(&blocks_module, block, options) + } else { + self.wasm_validate_inner(module, block, options) + } } } } else { @@ -525,7 +538,18 @@ where let output = instance.run(module)?; match output { - fuel_core_wasm_executor::utils::ReturnType::V1(result) => result, + ReturnType::ExecutionV0(result) => { + convert_from_v0_execution_result(result) + }, + ReturnType::ExecutionV1(result) => { + convert_from_v1_execution_result(result) + } + ReturnType::Validation(_) => { + Err(ExecutorError::Other( + "The WASM executor returned a validation result instead of an execution result" + .to_string(), + )) + } } } @@ -559,9 +583,14 @@ where let output = instance.run(module)?; match output { - fuel_core_wasm_executor::utils::ReturnType::V1(result) => { - Ok(result?.into_validation_result()) + ReturnType::ExecutionV0(result) => { + Ok(convert_from_v0_execution_result(result)?.into_validation_result()) } + ReturnType::ExecutionV1(result) => { + let result = convert_from_v1_execution_result(result)?; + Ok(result.into_validation_result()) + } + ReturnType::Validation(result) => Ok(result?), } } @@ -647,6 +676,16 @@ where return Err(UpgradableError::IncompleteUploadedBytecode(bytecode_root)) }; + // If the bytecode is the same as the native executor, we don't need to compile it. + if bytecode == crate::WASM_BYTECODE { + let engine = private::DEFAULT_ENGINE.get_or_init(wasmtime::Engine::default); + let module = private::COMPILED_UNDERLYING_EXECUTOR.get_or_init(|| { + wasmtime::Module::new(engine, crate::WASM_BYTECODE) + .expect("Failed to validate the WASM bytecode") + }); + return Ok(module.clone()); + } + wasmtime::Module::new(&self.engine, bytecode) .map_err(|e| UpgradableError::InvalidWasm(e.to_string())) } @@ -658,13 +697,12 @@ where #[cfg(feature = "wasm-executor")] fn get_module( &self, - version: fuel_core_types::blockchain::header::StateTransitionBytecodeVersion, + version: StateTransitionBytecodeVersion, ) -> ExecutorResult { - let guard = self.cached_modules.lock(); + let mut guard = self.cached_modules.lock(); if let Some(module) = guard.get(&version) { return Ok(module.clone()); } - drop(guard); let view = StructuredStorage::new( self.storage_view_provider @@ -686,7 +724,7 @@ where UpgradableError::ExecutorError(err) => err })?; - self.cached_modules.lock().insert(version, module.clone()); + guard.insert(version, module.clone()); Ok(module) } } diff --git a/crates/services/upgradable-executor/src/instance.rs b/crates/services/upgradable-executor/src/instance.rs index 01f5ba41a23..1dfe0e2f04a 100644 --- a/crates/services/upgradable-executor/src/instance.rs +++ b/crates/services/upgradable-executor/src/instance.rs @@ -1,5 +1,8 @@ use fuel_core_executor::{ - executor::ExecutionOptions, + executor::{ + ExecutionOptions, + OnceTransactionsSource, + }, ports::{ MaybeCheckedTransaction, RelayerPort, @@ -53,6 +56,18 @@ use wasmtime::{ trait CallerHelper { /// Writes the encoded data to the memory at the provided pointer. fn write(&mut self, ptr: u32, encoded: &[u8]) -> anyhow::Result<()>; + + /// Peeks the next transactions from the source and returns the size of + /// the encoded transactions in bytes. + fn peek_next_txs_bytes( + &mut self, + source: Arc, + gas_limit: u64, + tx_number_limit: u16, + size_limit: u32, + ) -> anyhow::Result + where + Source: TransactionsSource; } impl<'a> CallerHelper for Caller<'a, ExecutionState> { @@ -63,6 +78,51 @@ impl<'a> CallerHelper for Caller<'a, ExecutionState> { .write(&mut store, ptr as usize, encoded) .map_err(|e| anyhow::anyhow!("Failed to write to the memory: {}", e)) } + + fn peek_next_txs_bytes( + &mut self, + source: Arc, + gas_limit: u64, + tx_number_limit: u16, + size_limit: u32, + ) -> anyhow::Result + where + Source: TransactionsSource, + { + let txs: Vec<_> = source + .next(gas_limit, tx_number_limit, size_limit) + .into_iter() + .map(|tx| match tx { + MaybeCheckedTransaction::CheckedTransaction(checked, _) => { + let checked: Checked = checked.into(); + let (tx, _) = checked.into(); + tx + } + MaybeCheckedTransaction::Transaction(tx) => tx, + }) + .collect(); + + let encoded_txs = postcard::to_allocvec(&txs).map_err(|e| { + ExecutorError::Other(format!( + "Failed encoding of the transactions for `peek_next_txs_size` function: {}", + e + )) + })?; + let encoded_size = u32::try_from(encoded_txs.len()).map_err(|e| { + ExecutorError::Other(format!( + "The encoded transactions are more \ + than `u32::MAX`. We support only wasm32: {}", + e + )) + })?; + + self.data_mut() + .next_transactions + .entry(encoded_size) + .or_default() + .push(encoded_txs); + Ok(encoded_size) + } } /// The state used by the host functions provided for the WASM executor. @@ -108,12 +168,26 @@ impl Instance { } impl Instance { - const LATEST_HOST_MODULE: &'static str = "host_v0"; + const V0_HOST_MODULE: &'static str = "host_v0"; + const V1_HOST_MODULE: &'static str = "host_v1"; - /// Adds a new host function to the instance. - pub fn add_method(&mut self, method: &str, func: Func) -> ExecutorResult<()> { + /// Adds a new host function to the `host_v0` module of the instance. + pub fn add_v0_method(&mut self, method: &str, func: Func) -> ExecutorResult<()> { self.linker - .define(&self.store, Self::LATEST_HOST_MODULE, method, func) + .define(&self.store, Self::V0_HOST_MODULE, method, func) + .map_err(|e| { + ExecutorError::Other(format!( + "Failed definition of the `{}` function: {}", + method, e + )) + })?; + Ok(()) + } + + /// Adds a new host function to the `host_v1` module of the instance. + pub fn add_v1_method(&mut self, method: &str, func: Func) -> ExecutorResult<()> { + self.linker + .define(&self.store, Self::V1_HOST_MODULE, method, func) .map_err(|e| { ExecutorError::Other(format!( "Failed definition of the `{}` function: {}", @@ -137,11 +211,13 @@ impl Instance { TxSource: TransactionsSource + Send + Sync + 'static, { let source = source.map(|source| Arc::new(source)); + let peek_next_txs_size_v0 = self.peek_next_txs_size_v0(source.clone()); + self.add_v0_method("peek_next_txs_size", peek_next_txs_size_v0)?; let peek_next_txs_size = self.peek_next_txs_size(source.clone()); - self.add_method("peek_next_txs_size", peek_next_txs_size)?; + self.add_v1_method("peek_next_txs_size", peek_next_txs_size)?; let consume_next_txs = self.consume_next_txs(); - self.add_method("consume_next_txs", consume_next_txs)?; + self.add_v0_method("consume_next_txs", consume_next_txs)?; Ok(Instance { store: self.store, @@ -150,21 +226,11 @@ impl Instance { }) } - pub fn no_source(mut self) -> ExecutorResult> { - let peek_next_txs_size = self.no_source_peek_next_txs_size(); - self.add_method("peek_next_txs_size", peek_next_txs_size)?; - - let consume_next_txs = self.consume_next_txs(); - self.add_method("consume_next_txs", consume_next_txs)?; - - Ok(Instance { - store: self.store, - linker: self.linker, - stage: Source {}, - }) + pub fn no_source(self) -> ExecutorResult> { + self.add_source::(None) } - fn peek_next_txs_size(&mut self, source: Option>) -> Func + fn peek_next_txs_size_v0(&mut self, source: Option>) -> Func where TxSource: TransactionsSource + Send + Sync + 'static, { @@ -175,47 +241,31 @@ impl Instance { return Ok(0); }; - let txs: Vec<_> = source - .next(gas_limit) - .into_iter() - .map(|tx| match tx { - MaybeCheckedTransaction::CheckedTransaction(checked, _) => { - let checked: Checked = checked.into(); - let (tx, _) = checked.into(); - tx - } - MaybeCheckedTransaction::Transaction(tx) => tx, - }) - .collect(); - - let encoded_txs = postcard::to_allocvec(&txs).map_err(|e| { - ExecutorError::Other(format!( - "Failed encoding of the transactions for `peek_next_txs_size` function: {}", - e - )) - })?; - let encoded_size = u32::try_from(encoded_txs.len()).map_err(|e| { - ExecutorError::Other(format!( - "The encoded transactions are more than `u32::MAX`. We support only wasm32: {}", - e - )) - })?; - - caller - .data_mut() - .next_transactions - .entry(encoded_size) - .or_default() - .push(encoded_txs); - Ok(encoded_size) + caller.peek_next_txs_bytes(source, gas_limit, u16::MAX, u32::MAX) }; Func::wrap(&mut self.store, closure) } - fn no_source_peek_next_txs_size(&mut self) -> Func { - let closure = - move |_: Caller<'_, ExecutionState>, _: u64| -> anyhow::Result { Ok(0) }; + fn peek_next_txs_size(&mut self, source: Option>) -> Func + where + TxSource: TransactionsSource + Send + Sync + 'static, + { + let closure = move |mut caller: Caller<'_, ExecutionState>, + gas_limit: u64, + tx_number_limit: u32, + size_limit: u32| + -> anyhow::Result { + let Some(source) = source.clone() else { + return Ok(0); + }; + + let tx_number_limit = u16::try_from(tx_number_limit).map_err(|e| { + anyhow::anyhow!("The number of transactions is more than `u16::MAX`: {e}") + })?; + + caller.peek_next_txs_bytes(source, gas_limit, tx_number_limit, size_limit) + }; Func::wrap(&mut self.store, closure) } @@ -251,10 +301,10 @@ impl Instance { let storage = Arc::new(storage); let storage_size_of_value = self.storage_size_of_value(storage.clone()); - self.add_method("storage_size_of_value", storage_size_of_value)?; + self.add_v0_method("storage_size_of_value", storage_size_of_value)?; let storage_get = self.storage_get(storage); - self.add_method("storage_get", storage_get)?; + self.add_v0_method("storage_get", storage_get)?; Ok(Instance { store: self.store, @@ -352,13 +402,13 @@ impl Instance { let relayer = Arc::new(relayer); let relayer_enabled = self.relayer_enabled(relayer.clone()); - self.add_method("relayer_enabled", relayer_enabled)?; + self.add_v0_method("relayer_enabled", relayer_enabled)?; let relayer_size_of_events = self.relayer_size_of_events(relayer); - self.add_method("relayer_size_of_events", relayer_size_of_events)?; + self.add_v0_method("relayer_size_of_events", relayer_size_of_events)?; let relayer_get_events = self.relayer_get_events(); - self.add_method("relayer_get_events", relayer_get_events)?; + self.add_v0_method("relayer_get_events", relayer_get_events)?; Ok(Instance { store: self.store, @@ -478,7 +528,6 @@ impl Instance { self.add_input_data(input) } - // pub fn add_validation_input_data( self, block: &Block, @@ -509,7 +558,7 @@ impl Instance { })?; let input = self.input(encoded_input, encoded_input_size); - self.add_method("input", input)?; + self.add_v0_method("input", input)?; Ok(Instance { store: self.store, diff --git a/crates/services/upgradable-executor/wasm-executor/Cargo.toml b/crates/services/upgradable-executor/wasm-executor/Cargo.toml index 397157a47da..687a338e046 100644 --- a/crates/services/upgradable-executor/wasm-executor/Cargo.toml +++ b/crates/services/upgradable-executor/wasm-executor/Cargo.toml @@ -27,13 +27,18 @@ fuel-core-storage = { workspace = true, default-features = false, features = [ fuel-core-types = { workspace = true, default-features = false, features = [ "alloc", ] } +fuel-core-types-v0 = { package = "fuel-core-types", version = "0.35.0", default-features = false, features = [ + "alloc", + "serde", +], optional = true } postcard = { workspace = true } serde = { workspace = true } +serde_json = { workspace = true, default-features = false } [dev-dependencies] proptest = { workspace = true } [features] default = ["std"] -std = [] +std = ["fuel-core-types-v0"] smt = ["fuel-core-storage/smt", "fuel-core-executor/smt"] diff --git a/crates/services/upgradable-executor/wasm-executor/src/ext.rs b/crates/services/upgradable-executor/wasm-executor/src/ext.rs index bafad827179..99a5bbdfeee 100644 --- a/crates/services/upgradable-executor/wasm-executor/src/ext.rs +++ b/crates/services/upgradable-executor/wasm-executor/src/ext.rs @@ -75,6 +75,19 @@ impl<'a, T> Ptr32Mut<'a, [T]> { mod host { use super::*; + #[link(wasm_import_module = "host_v1")] + extern "C" { + // TxSource API + + /// Returns the size of the next encoded transactions. + /// If the size is 0, there are no more transactions. + pub(crate) fn peek_next_txs_size( + gas_limit: u64, + tx_count_limit: u32, + size_limit: u32, + ) -> u32; + } + #[link(wasm_import_module = "host_v0")] extern "C" { // Initialization API @@ -84,10 +97,6 @@ mod host { // TxSource API - /// Returns the size of the next encoded transactions. - /// If the size is 0, there are no more transactions. - pub(crate) fn peek_next_txs_size(gas_limit: u64) -> u32; - /// Consumes the next transactions from the host. /// Calling this function before `peek_next_txs_size` do nothing. pub(crate) fn consume_next_txs(output_ptr: Ptr32Mut<[u8]>, output_size: u32); @@ -148,8 +157,13 @@ pub fn input(size: usize) -> anyhow::Result { } /// Gets the next transactions by using the host function. -pub fn next_transactions(gas_limit: u64) -> anyhow::Result> { - let next_size = unsafe { host::peek_next_txs_size(gas_limit) }; +pub fn next_transactions( + gas_limit: u64, + tx_count_limit: u16, + size_limit: u32, +) -> anyhow::Result> { + let next_size = + unsafe { host::peek_next_txs_size(gas_limit, tx_count_limit as u32, size_limit) }; if next_size == 0 { return Ok(Vec::new()); diff --git a/crates/services/upgradable-executor/wasm-executor/src/main.rs b/crates/services/upgradable-executor/wasm-executor/src/main.rs index 6065cae9ea2..155bce78ac1 100644 --- a/crates/services/upgradable-executor/wasm-executor/src/main.rs +++ b/crates/services/upgradable-executor/wasm-executor/src/main.rs @@ -15,21 +15,16 @@ use crate as fuel_core_wasm_executor; use crate::utils::{ + convert_to_v1_execution_result, InputDeserializationType, WasmDeserializationBlockTypes, }; use fuel_core_executor::executor::ExecutionInstance; -use fuel_core_storage::transactional::Changes; use fuel_core_types::{ blockchain::block::Block, services::{ block_producer::Components, - executor::{ - Error as ExecutorError, - ExecutionResult, - Result as ExecutorResult, - }, - Uncommitted, + executor::Error as ExecutorError, }, }; use fuel_core_wasm_executor::{ @@ -50,8 +45,7 @@ pub mod utils; #[no_mangle] pub extern "C" fn execute(input_len: u32) -> u64 { - let result = execute_without_commit(input_len); - let output = ReturnType::V1(result); + let output: ReturnType = execute_without_commit(input_len); let encoded = postcard::to_allocvec(&output).expect("Failed to encode the output"); let static_slice = encoded.leak(); pack_ptr_and_len( @@ -60,11 +54,16 @@ pub extern "C" fn execute(input_len: u32) -> u64 { ) } -pub fn execute_without_commit( - input_len: u32, -) -> ExecutorResult> { - let input = ext::input(input_len as usize) - .map_err(|e| ExecutorError::Other(e.to_string()))?; +pub fn execute_without_commit(input_len: u32) -> ReturnType { + let input = + ext::input(input_len as usize).map_err(|e| ExecutorError::Other(e.to_string())); + + let input = match input { + Ok(input) => input, + Err(err) => { + return ReturnType::ExecutionV1(Err(err.into())); + } + }; let (block, options) = match input { InputDeserializationType::V1 { block, options } => { @@ -100,28 +99,24 @@ pub fn execute_without_commit( fn execute_dry_run( instance: ExecutionInstance, block: Components, -) -> ExecutorResult> { - instance.produce_without_commit(block, true) +) -> ReturnType { + let result = instance.produce_without_commit(block, true); + ReturnType::ExecutionV1(convert_to_v1_execution_result(result)) } fn execute_production( instance: ExecutionInstance, block: Components, -) -> ExecutorResult> { - instance.produce_without_commit(block, false) +) -> ReturnType { + let result = instance.produce_without_commit(block, false); + ReturnType::ExecutionV1(convert_to_v1_execution_result(result)) } fn execute_validation( instance: ExecutionInstance, block: Block, -) -> ExecutorResult> { - let result = instance - .validate_without_commit(&block)? - .into_execution_result(block, vec![]); - - // TODO: Modify return type to differentiate between validation and production results - // https://github.com/FuelLabs/fuel-core/issues/1887 - Ok(result) +) -> ReturnType { + ReturnType::Validation(instance.validate_without_commit(&block).map_err(Into::into)) } fn use_wasm_tx_source(component: Components<()>) -> Components { diff --git a/crates/services/upgradable-executor/wasm-executor/src/tx_source.rs b/crates/services/upgradable-executor/wasm-executor/src/tx_source.rs index 772b8159103..1cbdf64bde9 100644 --- a/crates/services/upgradable-executor/wasm-executor/src/tx_source.rs +++ b/crates/services/upgradable-executor/wasm-executor/src/tx_source.rs @@ -13,7 +13,13 @@ impl WasmTxSource { } impl TransactionsSource for WasmTxSource { - fn next(&self, gas_limit: u64) -> Vec { - ext::next_transactions(gas_limit).expect("Failed to get next transactions") + fn next( + &self, + gas_limit: u64, + tx_count_limit: u16, + size_limit: u32, + ) -> Vec { + ext::next_transactions(gas_limit, tx_count_limit, size_limit) + .expect("Failed to get next transactions") } } diff --git a/crates/services/upgradable-executor/wasm-executor/src/utils.rs b/crates/services/upgradable-executor/wasm-executor/src/utils.rs index 85047b28492..226b972bf43 100644 --- a/crates/services/upgradable-executor/wasm-executor/src/utils.rs +++ b/crates/services/upgradable-executor/wasm-executor/src/utils.rs @@ -5,12 +5,16 @@ use fuel_core_types::{ services::{ block_producer::Components, executor::{ + Error as ExecutorError, ExecutionResult, - Result as ExecutorResult, + UncommittedResult, + ValidationResult, }, Uncommitted, }, }; +#[cfg(feature = "std")] +use fuel_core_types_v0::services::executor::Error as ExecutorErrorV0; /// Pack a pointer and length into an `u64`. pub fn pack_ptr_and_len(ptr: u32, len: u32) -> u64 { @@ -80,16 +84,167 @@ pub enum WasmDeserializationBlockTypes { Validation(Block), } +/// The JSON version of the executor error. The serialization and deserialization +/// of the JSON error are less sensitive to the order of the variants in the enum. +/// It simplifies the error conversion between different versions of the execution. +/// +/// If deserialization fails, it returns a string representation of the error that +/// still has useful information, even if the error is not supported by the native executor. +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct JSONError(String); + +#[cfg(feature = "std")] +impl From for JSONError { + fn from(value: ExecutorErrorV0) -> Self { + let json = serde_json::to_string(&value).unwrap_or_else(|e| { + anyhow::anyhow!("Failed to serialize the V0 error: {:?}", e).to_string() + }); + JSONError(json) + } +} + +impl From for JSONError { + fn from(value: ExecutorError) -> Self { + let json = serde_json::to_string(&value).unwrap_or_else(|e| { + anyhow::anyhow!("Failed to serialize the error: {:?}", e).to_string() + }); + JSONError(json) + } +} + +impl From for ExecutorError { + fn from(value: JSONError) -> Self { + serde_json::from_str(&value.0).unwrap_or(ExecutorError::Other(value.0)) + } +} + /// The return type for the WASM executor. Enum allows handling different /// versions of the return without introducing new host functions. +#[cfg(feature = "std")] #[derive(Debug, serde::Serialize, serde::Deserialize)] pub enum ReturnType { - V1(ExecutorResult>), + ExecutionV0( + Result, Changes>, ExecutorErrorV0>, + ), + ExecutionV1(Result, Changes>, JSONError>), + Validation(Result, JSONError>), +} + +/// The return type for the WASM executor. Enum allows handling different +/// versions of the return without introducing new host functions. +#[cfg(not(feature = "std"))] +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub enum ReturnType { + /// WASM executor doesn't use this variant, so from its perspective it is empty. + ExecutionV0, + ExecutionV1(Result, Changes>, JSONError>), + Validation(Result, JSONError>), +} + +/// Converts the latest execution result to the `ExecutionV1`. +pub fn convert_to_v1_execution_result( + result: Result, ExecutorError>, +) -> Result, Changes>, JSONError> { + result + .map(|result| { + let (result, changes) = result.into(); + let ExecutionResult { + block, + skipped_transactions, + tx_status, + events, + } = result; + + let skipped_transactions: Vec<_> = skipped_transactions + .into_iter() + .map(|(id, error)| (id, JSONError::from(error))) + .collect(); + + let result = ExecutionResult { + block, + skipped_transactions, + tx_status, + events, + }; + + Uncommitted::new(result, changes) + }) + .map_err(JSONError::from) +} + +/// Converts the `ExecutionV1` to latest execution result. +pub fn convert_from_v1_execution_result( + result: Result, Changes>, JSONError>, +) -> Result, ExecutorError> { + result + .map(|result| { + let (result, changes) = result.into(); + let ExecutionResult { + block, + skipped_transactions, + tx_status, + events, + } = result; + + let skipped_transactions: Vec<_> = skipped_transactions + .into_iter() + .map(|(id, error)| (id, ExecutorError::from(error))) + .collect(); + + let result = ExecutionResult { + block, + skipped_transactions, + tx_status, + events, + }; + + Uncommitted::new(result, changes) + }) + .map_err(ExecutorError::from) +} + +/// Converts the `ExecutionV0` to latest execution result. +#[cfg(feature = "std")] +pub fn convert_from_v0_execution_result( + result: Result< + Uncommitted, Changes>, + ExecutorErrorV0, + >, +) -> Result, ExecutorError> { + result + .map(|result| { + let (result, changes) = result.into(); + let ExecutionResult { + block, + skipped_transactions, + tx_status, + events, + } = result; + + let skipped_transactions: Vec<_> = skipped_transactions + .into_iter() + .map(|(id, error)| (id, ExecutorError::from(JSONError::from(error)))) + .collect(); + + let result = ExecutionResult { + block, + skipped_transactions, + tx_status, + events, + }; + + Uncommitted::new(result, changes) + }) + .map_err(JSONError::from) + .map_err(ExecutorError::from) } #[cfg(test)] mod tests { use super::*; + use fuel_core_types::services::executor::TransactionValidityError; + #[cfg(feature = "std")] + use fuel_core_types_v0::services::executor::TransactionValidityError as TransactionValidityErrorV0; use proptest::prelude::prop::*; proptest::proptest! { @@ -115,4 +270,25 @@ mod tests { proptest::prop_assert_eq!(result, unpacked_result); } } + + #[cfg(feature = "std")] + #[test] + fn can_convert_v0_error_to_v1() { + // Given + let v0 = ExecutorErrorV0::TransactionValidity( + TransactionValidityErrorV0::CoinDoesNotExist(Default::default()), + ); + + // When + let json: JSONError = v0.into(); + let v1: ExecutorError = json.into(); + + // Then + assert_eq!( + v1, + ExecutorError::TransactionValidity( + TransactionValidityError::CoinDoesNotExist(Default::default()) + ) + ); + } } diff --git a/crates/types/src/services/block_producer.rs b/crates/types/src/services/block_producer.rs index 6df220a0577..e6b24b26ee2 100644 --- a/crates/types/src/services/block_producer.rs +++ b/crates/types/src/services/block_producer.rs @@ -10,6 +10,7 @@ use crate::{ /// The components required to produce a block. #[derive(Debug)] +#[cfg_attr(any(test, feature = "test-helpers"), derive(Default))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Components { /// The partial block header of the future block without transactions related information. diff --git a/crates/types/src/services/executor.rs b/crates/types/src/services/executor.rs index 67ce6ca73c4..4e2826eb2f0 100644 --- a/crates/types/src/services/executor.rs +++ b/crates/types/src/services/executor.rs @@ -51,21 +51,32 @@ pub type UncommittedValidationResult = Uncommitted; /// The result of transactions execution for block production. -#[cfg_attr(any(test, feature = "test-helpers"), derive(Default))] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] -pub struct ExecutionResult { +pub struct ExecutionResult { /// Created block during the execution of transactions. It contains only valid transactions. pub block: Block, /// The list of skipped transactions with corresponding errors. Those transactions were /// not included in the block and didn't affect the state of the blockchain. - pub skipped_transactions: Vec<(TxId, Error)>, + pub skipped_transactions: Vec<(TxId, E)>, /// The status of the transactions execution included into the block. pub tx_status: Vec, /// The list of all events generated during the execution of the block. pub events: Vec, } +#[cfg(any(test, feature = "test-helpers"))] +impl Default for ExecutionResult { + fn default() -> Self { + Self { + block: Block::default(), + skipped_transactions: Default::default(), + tx_status: Default::default(), + events: Default::default(), + } + } +} + /// The result of the validation of the block. #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[derive(Debug)] @@ -246,6 +257,9 @@ pub enum Error { TransactionIdCollision(Bytes32), #[display(fmt = "Too many transactions in the block")] TooManyTransactions, + /// Number of outputs is more than `u16::MAX`. + #[display(fmt = "Number of outputs is more than `u16::MAX`")] + TooManyOutputs, #[display(fmt = "output already exists")] OutputAlreadyExists, #[display(fmt = "The computed fee caused an integer overflow")] @@ -313,9 +327,6 @@ pub enum Error { /// It is possible to occur untyped errors in the case of the upgrade. #[display(fmt = "Occurred untyped error: {_0}")] Other(String), - /// Number of outputs is more than `u16::MAX`. - #[display(fmt = "Number of outputs is more than `u16::MAX`")] - TooManyOutputs, } impl From for anyhow::Error { diff --git a/deployment/e2e-client.Dockerfile b/deployment/e2e-client.Dockerfile index 452bdf7d884..1d2077aad4e 100644 --- a/deployment/e2e-client.Dockerfile +++ b/deployment/e2e-client.Dockerfile @@ -17,11 +17,11 @@ FROM chef as builder ENV CARGO_NET_GIT_FETCH_WITH_CLI=true COPY --from=planner /build/recipe.json recipe.json # Build our project dependencies, not our application! -RUN cargo chef cook --release -p fuel-core-e2e-client --features p2p --recipe-path recipe.json +RUN cargo chef cook --release -p fuel-core-e2e-client --recipe-path recipe.json # Up to this point, if our dependency tree stays the same, # all layers should be cached. COPY . . -RUN cargo build --release -p fuel-core-e2e-client --features p2p +RUN cargo build --release -p fuel-core-e2e-client # Stage 2: Run FROM ubuntu:22.04 as run diff --git a/tests/test-helpers/src/builder.rs b/tests/test-helpers/src/builder.rs index 0640024395d..57e20441a29 100644 --- a/tests/test-helpers/src/builder.rs +++ b/tests/test-helpers/src/builder.rs @@ -206,6 +206,8 @@ impl TestSetupBuilder { chain_conf .consensus_parameters .set_base_asset_id(self.base_asset_id); + chain_conf.state_transition_bytecode = + fuel_core::upgradable_executor::WASM_BYTECODE.to_vec(); let latest_block = self.starting_block.map(|starting_block| LastBlockConfig { block_height: starting_block, diff --git a/version-compatibility/Cargo.toml b/version-compatibility/Cargo.toml index e562a8ee52e..05c5d3d8831 100644 --- a/version-compatibility/Cargo.toml +++ b/version-compatibility/Cargo.toml @@ -1,10 +1,6 @@ [workspace] resolver = "2" -members = [ - # Add new versions here when testing backwards compatibility between fuel-core-client and fuel-core - "placeholder", - "forkless-upgrade", -] +members = ["forkless-upgrade"] # exclude previous versions no longer maintained exclude = [ diff --git a/version-compatibility/forkless-upgrade/Cargo.toml b/version-compatibility/forkless-upgrade/Cargo.toml index 07366c030a8..33411ab9388 100644 --- a/version-compatibility/forkless-upgrade/Cargo.toml +++ b/version-compatibility/forkless-upgrade/Cargo.toml @@ -25,10 +25,14 @@ latest-fuel-core-bin = { path = "../../bin/fuel-core", package = "fuel-core-bin" "parquet", "p2p", ] } -latest-fuel-core-client = { path = "../../crates/client", package = "fuel-core-client" } -latest-fuel-core-upgradable-executor = { path = "../../crates/services/upgradable-executor", package = "fuel-core-upgradable-executor", features = [ - "wasm-executor", +latest-fuel-core-type = { path = "../../crates/types", package = "fuel-core-types", features = [ + "test-helpers", ] } +latest-fuel-core-client = { path = "../../crates/client", package = "fuel-core-client" } +# TODO: https://github.com/FuelLabs/fuel-core/issues/2198 +#latest-fuel-core-upgradable-executor = { path = "../../crates/services/upgradable-executor", package = "fuel-core-upgradable-executor", features = [ +# "wasm-executor", +#] } # Genesis fuel-core genesis-fuel-core-bin = { version = "0.26.0", package = "fuel-core-bin", features = [ diff --git a/version-compatibility/forkless-upgrade/src/backward_compatibility.rs b/version-compatibility/forkless-upgrade/src/backward_compatibility.rs index 7db2180b42b..229f9eadb75 100644 --- a/version-compatibility/forkless-upgrade/src/backward_compatibility.rs +++ b/version-compatibility/forkless-upgrade/src/backward_compatibility.rs @@ -2,9 +2,19 @@ use crate::tests_helper::{ default_multiaddr, GenesisFuelCoreDriver, LatestFuelCoreDriver, - IGNITION_SNAPSHOT, + IGNITION_TESTNET_SNAPSHOT, POA_SECRET_KEY, }; +use latest_fuel_core_type::{ + fuel_tx::Transaction, + services::{ + block_producer::Components, + executor::{ + Error as ExecutorError, + TransactionValidityError, + }, + }, +}; use libp2p::{ futures::StreamExt, identity::{ @@ -23,7 +33,7 @@ async fn latest_binary_is_backward_compatible_and_can_load_testnet_config() { "--poa-instant", "true", "--snapshot", - IGNITION_SNAPSHOT, + IGNITION_TESTNET_SNAPSHOT, // We need to set the native executor version to 1 to be // sure it is not zero to force the usage of the WASM executor "--native-executor-version", @@ -52,7 +62,7 @@ async fn latest_binary_is_backward_compatible_and_follows_blocks_created_by_gene "--consensus-key", POA_SECRET_KEY, "--snapshot", - IGNITION_SNAPSHOT, + IGNITION_TESTNET_SNAPSHOT, "--enable-p2p", "--keypair", hexed_secret.as_str(), @@ -76,7 +86,7 @@ async fn latest_binary_is_backward_compatible_and_follows_blocks_created_by_gene "--poa-instant", "false", "--snapshot", - IGNITION_SNAPSHOT, + IGNITION_TESTNET_SNAPSHOT, "--enable-p2p", "--keypair", hexed_secret.as_str(), @@ -105,3 +115,55 @@ async fn latest_binary_is_backward_compatible_and_follows_blocks_created_by_gene .expect(format!("Failed to import block {i}").as_str()); } } + +#[tokio::test] +async fn latest_binary_is_backward_compatible_and_can_deserialize_errors_from_genesis_binary( +) { + // Given + let genesis_keypair = SecpKeypair::generate(); + let hexed_secret = hex::encode(genesis_keypair.secret().to_bytes()); + let genesis_port = "30333"; + let node_with_genesis_transition = LatestFuelCoreDriver::spawn(&[ + "--service-name", + "GenesisProducer", + "--debug", + "--poa-instant", + "true", + "--consensus-key", + POA_SECRET_KEY, + "--snapshot", + IGNITION_TESTNET_SNAPSHOT, + "--enable-p2p", + "--keypair", + hexed_secret.as_str(), + "--peering-port", + genesis_port, + "--utxo-validation", + ]) + .await + .unwrap(); + + // When + let invalid_transaction = Transaction::default_test_tx(); + let mut component: Components> = Default::default(); + component.header_to_produce.consensus.height = 1u32.into(); + // Use version of the genesis state transition + component + .header_to_produce + .application + .state_transition_bytecode_version = 0; + component.transactions_source = vec![invalid_transaction]; + let result = node_with_genesis_transition + .node + .shared + .executor + .produce_without_commit_from_vector(component); + + // Then + let result = result.expect("Should dry run without error").into_result(); + assert_eq!(result.skipped_transactions.len(), 1); + assert!(matches!( + result.skipped_transactions[0].1, + ExecutorError::TransactionValidity(TransactionValidityError::CoinDoesNotExist(_)) + )); +} diff --git a/version-compatibility/forkless-upgrade/src/forward_compatibility.rs b/version-compatibility/forkless-upgrade/src/forward_compatibility.rs index c87d9ea5e42..f18b19b78cf 100644 --- a/version-compatibility/forkless-upgrade/src/forward_compatibility.rs +++ b/version-compatibility/forkless-upgrade/src/forward_compatibility.rs @@ -7,7 +7,7 @@ use crate::tests_helper::{ transactions_from_subsections, upgrade_transaction, GenesisFuelCoreDriver, - IGNITION_SNAPSHOT, + IGNITION_TESTNET_SNAPSHOT, POA_SECRET_KEY, SUBSECTION_SIZE, }; @@ -55,7 +55,7 @@ async fn latest_state_transition_function_is_forward_compatible_with_genesis_bin "--consensus-key", POA_SECRET_KEY, "--snapshot", - IGNITION_SNAPSHOT, + IGNITION_TESTNET_SNAPSHOT, "--enable-p2p", "--keypair", hexed_secret.as_str(), @@ -79,7 +79,7 @@ async fn latest_state_transition_function_is_forward_compatible_with_genesis_bin "--poa-instant", "false", "--snapshot", - IGNITION_SNAPSHOT, + IGNITION_TESTNET_SNAPSHOT, "--enable-p2p", "--keypair", hexed_secret.as_str(), diff --git a/version-compatibility/forkless-upgrade/src/lib.rs b/version-compatibility/forkless-upgrade/src/lib.rs index b40ca55c722..27583513f45 100644 --- a/version-compatibility/forkless-upgrade/src/lib.rs +++ b/version-compatibility/forkless-upgrade/src/lib.rs @@ -3,8 +3,11 @@ #[cfg(test)] mod backward_compatibility; -#[cfg(test)] -mod forward_compatibility; +// TODO: Uncomment forward compatibility tests after release of the `fuel-core 0.36.0`. +// New forward compatibility test should use the `fuel-core 0.36.0`. +// https://github.com/FuelLabs/fuel-core/issues/2198 +// #[cfg(test)] +// mod forward_compatibility; #[cfg(test)] pub(crate) mod tests_helper; diff --git a/version-compatibility/forkless-upgrade/src/tests_helper.rs b/version-compatibility/forkless-upgrade/src/tests_helper.rs index 504120353f7..617b7403204 100644 --- a/version-compatibility/forkless-upgrade/src/tests_helper.rs +++ b/version-compatibility/forkless-upgrade/src/tests_helper.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use fuel_crypto::{ fuel_types::ChainId, SecretKey, @@ -42,7 +44,6 @@ macro_rules! define_core_driver { /// This must be before the _db_dir as the drop order matters here. pub node: $service, pub _db_dir: tempfile::TempDir, - #[allow(dead_code)] // Only some of the clients generated by this macro are used pub client: $client, } @@ -63,9 +64,12 @@ macro_rules! define_core_driver { ]; args.extend(extra_args); - let node = maybe_await!($bin_crate_get_service_is_async, $bin_crate::cli::run::get_service( - $bin_crate::cli::run::Command::parse_from(args), - ))?; + let node = maybe_await!( + $bin_crate_get_service_is_async, + $bin_crate::cli::run::get_service( + $bin_crate::cli::run::Command::parse_from(args), + ) + )?; node.start_and_await().await?; @@ -96,7 +100,7 @@ define_core_driver!( true ); -pub const IGNITION_SNAPSHOT: &str = "./chain-configurations/ignition"; +pub const IGNITION_TESTNET_SNAPSHOT: &str = "./chain-configurations/ignition"; pub const POA_SECRET_KEY: &str = "e3d6eb39607650e22f0befa26d52e921d2e7924d0e165f38ffa8d9d0ac73de93"; pub const PRIVILEGED_ADDRESS_KEY: &str = diff --git a/version-compatibility/placeholder/Cargo.toml b/version-compatibility/placeholder/Cargo.toml deleted file mode 100644 index 41e4a7285cc..00000000000 --- a/version-compatibility/placeholder/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "placeholder" -version = "0.1.0" -edition = "2021" -publish = false -license = "BUSL-1.1" -description = "placeholder for version compatibility tests" - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] diff --git a/version-compatibility/placeholder/src/main.rs b/version-compatibility/placeholder/src/main.rs deleted file mode 100644 index e7a11a969c0..00000000000 --- a/version-compatibility/placeholder/src/main.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("Hello, world!"); -}