diff --git a/CHANGELOG.md b/CHANGELOG.md index c88dec1fa2f..2362c8085b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - [1983](https://github.com/FuelLabs/fuel-core/pull/1983): Add adapters for gas price service for accessing database values ### Breaking +- [#1988](https://github.com/FuelLabs/fuel-core/pull/1988): Updated `fuel-vm` to `0.56.0` ([release notes](https://github.com/FuelLabs/fuel-vm/releases/tag/v0.55.0)). Adds Blob transaction support. - [2025](https://github.com/FuelLabs/fuel-core/pull/2025): Add new V0 algorithm for gas price to services. This change includes new flags for the CLI: - "starting-gas-price" - the starting gas price for the gas price algorithm diff --git a/Cargo.lock b/Cargo.lock index e59aa499364..f3e7def4f41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2772,9 +2772,9 @@ dependencies = [ [[package]] name = "fuel-asm" -version = "0.55.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "491f1777538b0e1d479609d0d75bca5242c7fd3394f2ddd4ea55b8c96bcc8387" +checksum = "122c27ab46707017063bf1c6e0b4f3de881e22e81b4059750a0dc95033d9cc26" dependencies = [ "bitflags 2.6.0", "fuel-types", @@ -3394,9 +3394,9 @@ dependencies = [ [[package]] name = "fuel-crypto" -version = "0.55.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f74f03ba9b27f375a0482b1afe20d5b8cfd032fedba683a584cdbd6d10147439" +checksum = "33548590131674e8f272a3e056be4dbaa1de7cb364eab2b17987cd5c0dc31cb0" dependencies = [ "coins-bip32", "coins-bip39", @@ -3415,9 +3415,9 @@ dependencies = [ [[package]] name = "fuel-derive" -version = "0.55.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ad30ad1a11e5a811ae67b6b0cb6785ce21bcd5ef0afd442fd963d5be95d09d" +checksum = "3f49fdbfc1615d88d2849650afc2b0ac2fecd69661ebadd31a073d8416747764" dependencies = [ "proc-macro2", "quote", @@ -3436,9 +3436,9 @@ dependencies = [ [[package]] name = "fuel-merkle" -version = "0.55.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5433c41ffbf531eed1380148cd68e37f9dd7e25966a9c59518f6b09e346e80e2" +checksum = "cf17ce8ee5e8b573ea584c223635ff09f1288ad022bcf662954fdccb907602eb" dependencies = [ "derive_more", "digest 0.10.7", @@ -3451,15 +3451,15 @@ dependencies = [ [[package]] name = "fuel-storage" -version = "0.55.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce3fc3cd96fe312442cdf35966b96d66becd02582b505f856f74953f57adf020" +checksum = "4c1b711f28553ddc5f3546711bd220e144ce4c1af7d9e9a1f70b2f20d9f5b791" [[package]] name = "fuel-tx" -version = "0.55.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e00cc42ae3121b1881a6ae8306696d1bea73adca424216d9f676ee91d3927c74" +checksum = "13aae44611588d199dd119e4a0ebd8eb7ae4cde6bf8b4d12715610b1f5e5b731" dependencies = [ "bitflags 2.6.0", "derivative", @@ -3480,9 +3480,9 @@ dependencies = [ [[package]] name = "fuel-types" -version = "0.55.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae98e143dec4e6cb114a92435e314f1d4815e17e8fded24332fb285319d60167" +checksum = "5b6fb26bcb408b6897e603f68cf60bbbaf6d15381c99f54a69ea743a58235ac1" dependencies = [ "fuel-derive", "hex", @@ -3492,9 +3492,9 @@ dependencies = [ [[package]] name = "fuel-vm" -version = "0.55.0" +version = "0.56.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "641a2ee5a3398633fa243fba3343cbe2225ae335a09141f6b94041720cfc3520" +checksum = "64fc4695efac9207276f6229f2dd9811848b328a13604a698f7bce1d452bd986" dependencies = [ "anyhow", "async-trait", diff --git a/Cargo.toml b/Cargo.toml index c19705bc988..05e8cc31a3e 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.31.0", path = "crates/fuel-gas-price-algorithm" } # Fuel dependencies -fuel-vm-private = { version = "0.55.0", package = "fuel-vm", default-features = false } +fuel-vm-private = { version = "0.56.0", package = "fuel-vm", default-features = false } # Common dependencies anyhow = "1.0" diff --git a/benches/benches-outputs/src/lib.rs b/benches/benches-outputs/src/lib.rs index 9265d936d19..5ff79c3ae70 100644 --- a/benches/benches-outputs/src/lib.rs +++ b/benches/benches-outputs/src/lib.rs @@ -1,5 +1,5 @@ use fuel_core_types::fuel_tx::{ - consensus_parameters::gas::GasCostsValuesV3, + consensus_parameters::gas::GasCostsValuesV4, DependentCost, GasCostsValues, }; diff --git a/benches/benches/block_target_gas_set/contract.rs b/benches/benches/block_target_gas_set/contract.rs index de32d773d16..df359e3c4d0 100644 --- a/benches/benches/block_target_gas_set/contract.rs +++ b/benches/benches/block_target_gas_set/contract.rs @@ -217,7 +217,7 @@ pub fn run_contract(group: &mut BenchmarkGroup) { let mut instructions = setup_instructions(); instructions.extend(vec![ op::movi(0x13, size), - op::ldc(CONTRACT_ID_REGISTER, RegId::ZERO, 0x13), + op::ldc(CONTRACT_ID_REGISTER, RegId::ZERO, 0x13, 0), op::jmpb(RegId::ZERO, 0), ]); let id = format!("contract/ldc {:?}", size); diff --git a/benches/benches/block_target_gas_set/crypto.rs b/benches/benches/block_target_gas_set/crypto.rs index fd53a7c0a1b..d33b9020b1a 100644 --- a/benches/benches/block_target_gas_set/crypto.rs +++ b/benches/benches/block_target_gas_set/crypto.rs @@ -97,43 +97,46 @@ pub fn run_crypto(group: &mut BenchmarkGroup) { .collect(), ); - let message = Message::new(b"foo"); let ed19_secret = ed25519_dalek::SigningKey::generate(&mut rand::rngs::OsRng {}); let ed19_signature = ed19_secret.sign(&*message); - run( - "crypto/ed19 opcode", - group, - vec![ - op::gtf_args(0x20, 0x00, GTFArgs::ScriptData), - op::addi( - 0x21, - 0x20, - ed19_secret - .verifying_key() - .as_ref() - .len() - .try_into() - .unwrap(), - ), - op::addi( - 0x22, - 0x21, - ed19_signature.to_bytes().len().try_into().unwrap(), - ), - op::addi(0x22, 0x21, message.as_ref().len().try_into().unwrap()), - op::ed19(0x20, 0x21, 0x22), - op::jmpb(RegId::ZERO, 0), - ], - ed19_secret - .verifying_key() - .to_bytes() - .iter() - .copied() - .chain(ed19_signature.to_bytes()) - .chain(message.as_ref().iter().copied()) - .collect(), - ); + for i in arb_dependent_cost_values() { + let id = format!("crypto/ed19 opcode {:?}", i); + let message = vec![1u8; i as usize]; + run( + &id, + group, + vec![ + op::gtf_args(0x20, 0x00, GTFArgs::ScriptData), + op::addi( + 0x21, + 0x20, + ed19_secret + .verifying_key() + .as_ref() + .len() + .try_into() + .unwrap(), + ), + op::addi( + 0x22, + 0x21, + ed19_signature.to_bytes().len().try_into().unwrap(), + ), + op::movi(0x23, message.len().try_into().unwrap()), + op::ed19(0x20, 0x21, 0x22, 0x23), + op::jmpb(RegId::ZERO, 0), + ], + ed19_secret + .verifying_key() + .to_bytes() + .iter() + .copied() + .chain(ed19_signature.to_bytes()) + .chain(message.iter().copied()) + .collect(), + ); + } for i in arb_dependent_cost_values() { let id = format!("crypto/s256 opcode {:?}", i); diff --git a/benches/benches/vm_set/blockchain.rs b/benches/benches/vm_set/blockchain.rs index 22d753d0b60..37bf630a448 100644 --- a/benches/benches/vm_set/blockchain.rs +++ b/benches/benches/vm_set/blockchain.rs @@ -358,7 +358,7 @@ pub fn run(c: &mut Criterion) { run_group_ref( &mut ldc, format!("{i}"), - VmBench::new(op::ldc(0x10, RegId::ZERO, 0x13)) + VmBench::new(op::ldc(0x10, RegId::ZERO, 0x13, 0)) .with_contract_code(code) .with_data(data) .with_prepare_script(prepare_script), diff --git a/benches/benches/vm_set/crypto.rs b/benches/benches/vm_set/crypto.rs index f7f886234af..cb266a4df36 100644 --- a/benches/benches/vm_set/crypto.rs +++ b/benches/benches/vm_set/crypto.rs @@ -114,37 +114,44 @@ pub fn run(c: &mut Criterion) { let ed19_secret = ed25519_dalek::SigningKey::generate(&mut rand::rngs::OsRng {}); let ed19_signature = ed19_secret.sign(&*message); - run_group_ref( - &mut c.benchmark_group("ed19"), - "ed19", - VmBench::new(op::ed19(0x20, 0x21, 0x22)) - .with_prepare_script(vec![ - op::gtf_args(0x20, 0x00, GTFArgs::ScriptData), - op::addi( - 0x21, - 0x20, + let mut bench_ed19 = c.benchmark_group("ed19"); + for i in &linear { + bench_ed19.throughput(Throughput::Bytes(*i as u64)); + run_group_ref( + &mut bench_ed19, + format!("{i}"), + VmBench::new(op::ed19(0x20, 0x21, RegId::ZERO, 0x10)) + .with_prepare_script(vec![ + op::gtf_args(0x20, 0x00, GTFArgs::ScriptData), + op::addi( + 0x21, + 0x20, + ed19_secret + .verifying_key() + .as_bytes() + .len() + .try_into() + .unwrap(), + ), + op::addi( + 0x22, + 0x21, + ed19_signature.to_bytes().len().try_into().unwrap(), + ), + op::movi(0x10, *i), + op::cfe(0x10), + ]) + .with_data( ed19_secret .verifying_key() - .as_bytes() - .len() - .try_into() - .unwrap(), - ), - op::addi( - 0x22, - 0x21, - ed19_signature.to_bytes().len().try_into().unwrap(), + .to_bytes() + .iter() + .chain(ed19_signature.to_bytes().iter()) + .chain(message.iter()) + .copied() + .collect(), ), - ]) - .with_data( - ed19_secret - .verifying_key() - .to_bytes() - .iter() - .chain(ed19_signature.to_bytes().iter()) - .chain(message.iter()) - .copied() - .collect(), - ), - ); + ); + } + bench_ed19.finish(); } diff --git a/benches/src/bin/collect.rs b/benches/src/bin/collect.rs index e88190ab526..4dee5114b4f 100644 --- a/benches/src/bin/collect.rs +++ b/benches/src/bin/collect.rs @@ -1,6 +1,6 @@ use clap::Parser; use fuel_core_types::fuel_tx::{ - consensus_parameters::gas::GasCostsValuesV3, + consensus_parameters::gas::GasCostsValuesV4, ConsensusParameters, GasCosts, }; @@ -371,7 +371,7 @@ pub const GIT: &str = ""#, r#"";"#, r##" pub fn default_gas_costs() -> GasCostsValues { - GasCostsValuesV3 {"##, + GasCostsValuesV4 {"##, r##" }.into() } "##, @@ -495,7 +495,7 @@ impl State { ) } - fn to_gas_costs(&self) -> GasCostsValuesV3 { + fn to_gas_costs(&self) -> GasCostsValuesV4 { serde_yaml::from_value(self.to_yaml()).unwrap() } diff --git a/benches/src/default_gas_costs.rs b/benches/src/default_gas_costs.rs index 39beebb650b..59109081608 100644 --- a/benches/src/default_gas_costs.rs +++ b/benches/src/default_gas_costs.rs @@ -1,7 +1,7 @@ use super::*; -use fuel_core_types::fuel_tx::consensus_parameters::gas::GasCostsValuesV3; +use fuel_core_types::fuel_tx::consensus_parameters::gas::GasCostsValuesV4; pub fn default_gas_costs() -> GasCostsValues { - GasCostsValuesV3 { + GasCostsValuesV4 { add: 2, addi: 2, and: 2, @@ -16,7 +16,6 @@ pub fn default_gas_costs() -> GasCostsValues { divi: 2, eck1: 1907, ecr1: 26135, - ed19: 1893, eq: 2, exp: 2, expi: 2, @@ -95,6 +94,14 @@ pub fn default_gas_costs() -> GasCostsValues { base: 2, units_per_gas: 15, }, + bldd: DependentCost::LightOperation { + base: 15, + units_per_gas: 272, + }, + bsiz: DependentCost::LightOperation { + base: 17, + units_per_gas: 790, + }, cfe: DependentCost::LightOperation { base: 10, units_per_gas: 1818181, @@ -119,6 +126,10 @@ pub fn default_gas_costs() -> GasCostsValues { base: 31, units_per_gas: 438, }, + ed19: DependentCost::LightOperation { + base: 3000, + units_per_gas: 214, + }, k256: DependentCost::LightOperation { base: 27, units_per_gas: 5, diff --git a/bin/fuel-core/chainspec/local-testnet/chain_config.json b/bin/fuel-core/chainspec/local-testnet/chain_config.json index da714fd834d..fab10ca521f 100644 --- a/bin/fuel-core/chainspec/local-testnet/chain_config.json +++ b/bin/fuel-core/chainspec/local-testnet/chain_config.json @@ -40,7 +40,7 @@ }, "chain_id": 0, "gas_costs": { - "V3": { + "V4": { "add": 2, "addi": 2, "and": 2, @@ -55,7 +55,6 @@ "divi": 2, "eck1": 1907, "ecr1": 26135, - "ed19": 1893, "eq": 2, "exp": 2, "expi": 2, @@ -133,6 +132,18 @@ "units_per_gas": 15 } }, + "bsiz": { + "LightOperation": { + "base": 17, + "units_per_gas": 790 + } + }, + "bldd": { + "LightOperation": { + "base": 15, + "units_per_gas": 272 + } + }, "cfe": { "LightOperation": { "base": 10, @@ -169,6 +180,12 @@ "units_per_gas": 438 } }, + "ed19": { + "LightOperation": { + "base": 3000, + "units_per_gas": 214 + } + }, "k256": { "LightOperation": { "base": 27, diff --git a/bin/fuel-core/chainspec/local-testnet/state_config.json b/bin/fuel-core/chainspec/local-testnet/state_config.json index 3f844a7528e..b0f3e1c856a 100644 --- a/bin/fuel-core/chainspec/local-testnet/state_config.json +++ b/bin/fuel-core/chainspec/local-testnet/state_config.json @@ -119,6 +119,7 @@ } ], "messages": [], + "blobs": [], "contracts": [ { "contract_id": "7777777777777777777777777777777777777777777777777777777777777777", 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 f99b6530a5f..00fac70f7f7 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/snapshot.rs b/bin/fuel-core/src/cli/snapshot.rs index 9152d6977dd..0c03f73edfd 100644 --- a/bin/fuel-core/src/cli/snapshot.rs +++ b/bin/fuel-core/src/cli/snapshot.rs @@ -801,6 +801,7 @@ mod tests { StateConfig { coins: vec![], messages: vec![], + blobs: vec![], contracts: vec![randomly_chosen_contract], last_block: Some(latest_block), } diff --git a/crates/chain-config/src/config.rs b/crates/chain-config/src/config.rs index c081981764f..a24036d25bb 100644 --- a/crates/chain-config/src/config.rs +++ b/crates/chain-config/src/config.rs @@ -1,3 +1,4 @@ +mod blob; mod chain; mod coin; mod consensus; @@ -10,6 +11,7 @@ mod snapshot_metadata; mod state; mod table_entry; +pub use blob::*; pub use chain::*; pub use coin::*; pub use consensus::*; diff --git a/crates/chain-config/src/config/blob.rs b/crates/chain-config/src/config/blob.rs new file mode 100644 index 00000000000..59335c913cd --- /dev/null +++ b/crates/chain-config/src/config/blob.rs @@ -0,0 +1,57 @@ +use crate::{ + serialization::HexIfHumanReadable, + TableEntry, +}; +use fuel_core_types::{ + fuel_types::BlobId, + fuel_vm::{ + BlobBytes, + BlobData, + }, +}; +use serde::{ + Deserialize, + Serialize, +}; +use serde_with::serde_as; + +#[serde_as] +#[derive(Default, Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] +pub struct BlobConfig { + pub blob_id: BlobId, + #[serde_as(as = "HexIfHumanReadable")] + pub payload: Vec, +} + +#[cfg(feature = "test-helpers")] +impl crate::Randomize for BlobConfig { + fn randomize(mut rng: impl ::rand::Rng) -> Self { + use fuel_core_types::fuel_tx::BlobIdExt; + + let payload_len = rng.gen_range(32..128); + let mut payload = vec![0; payload_len as usize]; + rng.fill_bytes(&mut payload); + + let blob_id = BlobId::compute(&payload); + + Self { blob_id, payload } + } +} + +impl From> for BlobConfig { + fn from(value: TableEntry) -> Self { + BlobConfig { + blob_id: value.key, + payload: value.value.0.to_vec(), + } + } +} + +impl From for TableEntry { + fn from(config: BlobConfig) -> Self { + Self { + key: config.blob_id, + value: BlobBytes(config.payload), + } + } +} diff --git a/crates/chain-config/src/config/randomize.rs b/crates/chain-config/src/config/randomize.rs index d895195a6ba..4b17bc24a0a 100644 --- a/crates/chain-config/src/config/randomize.rs +++ b/crates/chain-config/src/config/randomize.rs @@ -42,6 +42,7 @@ use fuel_core_types::{ RegId, }, fuel_tx::{ + BlobId, ContractId, Transaction, TransactionBuilder, @@ -57,6 +58,8 @@ use fuel_core_types::{ Nonce, }, fuel_vm::{ + BlobBytes, + BlobData, Salt, Signature, }, @@ -93,6 +96,7 @@ macro_rules! delegating_impl { delegating_table_impl!( Coins, + BlobData, ContractsRawCode, ContractsState, ContractsAssets, @@ -111,6 +115,8 @@ impl Randomize for TableEntry { } delegating_impl!( + BlobBytes, + BlobId, DaBlockHeight, BlockHeight, Address, 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 532eb750faf..5ca3b25b10d 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 @@ -44,7 +44,7 @@ expression: json }, "chain_id": 0, "gas_costs": { - "V3": { + "V4": { "add": 1, "addi": 1, "and": 1, @@ -59,7 +59,6 @@ expression: json "divi": 1, "eck1": 951, "ecr1": 3000, - "ed19": 3000, "eq": 1, "exp": 1, "expi": 1, @@ -137,6 +136,18 @@ expression: json "units_per_gas": 214 } }, + "bsiz": { + "LightOperation": { + "base": 17, + "units_per_gas": 790 + } + }, + "bldd": { + "LightOperation": { + "base": 15, + "units_per_gas": 272 + } + }, "cfe": { "LightOperation": { "base": 2, @@ -173,6 +184,12 @@ expression: json "units_per_gas": 790 } }, + "ed19": { + "LightOperation": { + "base": 3000, + "units_per_gas": 214 + } + }, "k256": { "LightOperation": { "base": 11, diff --git a/crates/chain-config/src/config/state.rs b/crates/chain-config/src/config/state.rs index 550f76b5f56..c8fee0468fd 100644 --- a/crates/chain-config/src/config/state.rs +++ b/crates/chain-config/src/config/state.rs @@ -1,4 +1,5 @@ use super::{ + blob::BlobConfig, coin::CoinConfig, contract::ContractConfig, message::MessageConfig, @@ -33,6 +34,7 @@ use fuel_core_types::{ BlockHeight, Bytes32, }, + fuel_vm::BlobData, }; use itertools::Itertools; use serde::{ @@ -121,6 +123,9 @@ pub struct StateConfig { pub coins: Vec, /// Messages from Layer 1 pub messages: Vec, + /// Blobs + #[serde(default)] + pub blobs: Vec, /// Contracts pub contracts: Vec, /// Last block config. @@ -131,6 +136,7 @@ pub struct StateConfig { pub struct StateConfigBuilder { coins: Vec>, messages: Vec>, + blobs: Vec>, contract_state: Vec>, contract_balance: Vec>, contract_code: Vec>, @@ -141,6 +147,7 @@ impl StateConfigBuilder { pub fn merge(&mut self, builder: Self) -> &mut Self { self.coins.extend(builder.coins); self.messages.extend(builder.messages); + self.blobs.extend(builder.blobs); self.contract_state.extend(builder.contract_state); self.contract_balance.extend(builder.contract_balance); self.contract_code.extend(builder.contract_code); @@ -162,6 +169,7 @@ impl StateConfigBuilder { .into_iter() .map(|message| message.into()) .collect(); + let blobs = self.blobs.into_iter().map(|blob| blob.into()).collect(); let contract_ids = self .contract_code .iter() @@ -240,6 +248,7 @@ impl StateConfigBuilder { Ok(StateConfig { coins, messages, + blobs, contracts, last_block: latest_block_config, }) @@ -285,6 +294,7 @@ impl crate::Randomize for StateConfig { Self { coins: rand_collection(&mut rng, amount), messages: rand_collection(&mut rng, amount), + blobs: rand_collection(&mut rng, amount), contracts: rand_collection(&mut rng, amount), last_block: Some(LastBlockConfig { block_height: rng.gen(), @@ -320,6 +330,22 @@ impl AddTable for StateConfigBuilder { } } +impl AsTable for StateConfig { + fn as_table(&self) -> Vec> { + self.blobs + .clone() + .into_iter() + .map(|blob| blob.into()) + .collect() + } +} + +impl AddTable for StateConfigBuilder { + fn add(&mut self, entries: Vec>) { + self.blobs.extend(entries); + } +} + impl AsTable for StateConfig { fn as_table(&self) -> Vec> { self.contracts @@ -482,6 +508,12 @@ impl StateConfig { .sorted_by_key(|m| m.nonce) .collect(); + self.blobs = self + .blobs + .into_iter() + .sorted_by_key(|b| b.blob_id) + .collect(); + self.contracts = self .contracts .into_iter() @@ -525,6 +557,14 @@ impl StateConfig { builder.add(messages); + let blobs = reader + .read::()? + .into_iter() + .flatten_ok() + .try_collect()?; + + builder.add(blobs); + let contract_state = reader .read::()? .into_iter() @@ -667,6 +707,7 @@ mod tests { test_tables!( Coins, + BlobData, ContractsAssets, ContractsLatestUtxo, ContractsRawCode, @@ -684,7 +725,7 @@ mod tests { } #[test] - fn json_roundtrip_coins_and_messages() { + fn json_roundtrip_non_contract_related_tables() { let writer = |temp_dir: &Path| SnapshotWriter::json(temp_dir); let reader = |metadata: SnapshotMetadata, group_size: usize| { SnapshotReader::open_w_config(metadata, group_size).unwrap() @@ -692,6 +733,7 @@ mod tests { assert_roundtrip::(writer, reader); assert_roundtrip::(writer, reader); + assert_roundtrip::(writer, reader); } #[test] @@ -735,23 +777,21 @@ mod tests { let chain_config = ChainConfig::local_testnet(); macro_rules! write_in_fragments { - ($($fragment_ty: ty,)*) => { - [ + ($($fragment_ty: ty,)*) => {[ $({ let mut writer = create_writer(); writer .write(AsTable::<$fragment_ty>::as_table(&state_config)) .unwrap(); writer.partial_close().unwrap() - }),* - ] - } - } + ]} + } let fragments = write_in_fragments!( Coins, Messages, + BlobData, ContractsState, ContractsAssets, ContractsRawCode, diff --git a/crates/chain-config/src/config/state/snapshots/fuel_core_chain_config__config__state__writer__tests__json_snapshot_is_human_readable.snap b/crates/chain-config/src/config/state/snapshots/fuel_core_chain_config__config__state__writer__tests__json_snapshot_is_human_readable.snap index 32cbfcc5653..5199d07a9cd 100644 --- a/crates/chain-config/src/config/state/snapshots/fuel_core_chain_config__config__state__writer__tests__json_snapshot_is_human_readable.snap +++ b/crates/chain-config/src/config/state/snapshots/fuel_core_chain_config__config__state__writer__tests__json_snapshot_is_human_readable.snap @@ -41,53 +41,63 @@ expression: encoded_json "da_height": 13053614869271975353 } ], + "blobs": [ + { + "blob_id": "8acdb0431a136a5c0c100271704144e34aebe82cb426ced41461224e7798bceb", + "payload": "d32d676c0ac47af4243e53915a314986c779af574aaf987302fc76b2e205b24e6e2b" + }, + { + "blob_id": "fb57963e95792ded6eed1ddbf40329cc6bdcb91decb9042aba6385216d8c07e2", + "payload": "cb83691e8057f9e3ee966b281b5843029c002ea90022143aa9a8711d331894e545abb4a5ce6e6ae85ffb107712e030ddbe3a50f6a93ec455ff76b489e0f68a8a47ee42" + } + ], "contracts": [ { - "contract_id": "84b864d0bb6f5cbf7af5b0b53cd78457f2fdba800ab44572e67f47853001a494", - "code": "03d30a245ac74a02e26e45cb80ee1b9c00a93345ce5f12bea9ffe04748d6696c", - "tx_id": "6c3955d818bb1ab0e832877d628233e3e1d64f76b71a80ec4f332f4d1a6742c5", - "output_index": 23607, - "tx_pointer_block_height": 737809138, - "tx_pointer_tx_idx": 15803, + "contract_id": "6b97a1efc738a7508436290b7495f2fed59d0454463c189bb56cf0996c6acb1a", + "code": "48d6696c30631735193aea95b8f9082c10620c0d6e3fc9596b4538d0dc24bec3", + "tx_id": "1a6742c537f2bb32473b01b1dcb1caac942722a4787bb185e4791916926e5fdb", + "output_index": 8485, + "tx_pointer_block_height": 758127325, + "tx_pointer_tx_idx": 50052, "states": [ { - "key": "30631735193aea95b8f9082c10620c0d6e3fc9596b4538d0dc24bec371bb3e46", - "value": "34561f8892e604021ab96b632eafa229ec3dd885442b44972526c4e8ce25a041" + "key": "71bb3e4634561f8892e604021ab96b632eafa229ec3dd885442b44972526c4e8", + "value": "ce25a0416c3955d818bb1ab0e832877d628233e3e1d64f76b71a80ec4f332f4d" } ], "balances": [ { - "asset_id": "32473b01b1dcb1caac942722a4787bb185e4791916926e5fdb25dd842f736ab9", - "amount": 12588167786327338867 + "asset_id": "2f736ab973e87f53b4857842789a1dd59167629b3c5cabe47dbf48827ec0818e", + "amount": 2760603075432636416 } ] }, { - "contract_id": "ef8361ae6133519413ccda29b9e0c6a1123fa5c757b3d115c2db68d8248c05ec", - "code": "7f53b4857842789a1dd59167629b3c5cabe47dbf48827ec0818e00de4b297f04", - "tx_id": "dd5687fee73fac7a2c564da689e9da76e1430d191fbc937d42f74104aa291871", - "output_index": 63732, - "tx_pointer_block_height": 3604148409, - "tx_pointer_tx_idx": 17105, + "contract_id": "86cc533ae2e5151fa164130012dd3f09e8861767739da0c536da6da933caf851", + "code": "4b297f047c3beda43d6e9f9b1b1bc44cdfce3574e7f7f0b2de2323a06ebc356b", + "tx_id": "aa291871f4b9d120f76583a1da5d1123f2b8a0ac606b940a66e42efd782af520", + "output_index": 561, + "tx_pointer_block_height": 3943236114, + "tx_pointer_tx_idx": 63027, "states": [ { - "key": "7c3beda43d6e9f9b1b1bc44cdfce3574e7f7f0b2de2323a06ebc356bad614726", - "value": "b313d811012d4be723755687120a7c6df2389c373c8fbe06bda7a61120652668" + "key": "ad614726b313d811012d4be723755687120a7c6df2389c373c8fbe06bda7a611", + "value": "20652668dd5687fee73fac7a2c564da689e9da76e1430d191fbc937d42f74104" } ], "balances": [ { - "asset_id": "20f76583a1da5d1123f2b8a0ac606b940a66e42efd782af5203112331adc2ed6", - "amount": 10029194223911757044 + "asset_id": "1adc2ed6f402dca396bfe6dfa3ac8a57ea08860870fd515cf7ca6afb887dd1e0", + "amount": 504295306752149147 } ] } ], "last_block": { - "block_height": 2346951900, - "da_block_height": 14074420184374977699, - "consensus_parameters_version": 2019076799, - "state_transition_version": 1670454246, - "blocks_root": "dfa3ac8a57ea08860870fd515cf7ca6afb887dd1e09be8e451cd3c364076623c" + "block_height": 1958882788, + "da_block_height": 7511963279655444049, + "consensus_parameters_version": 3579832892, + "state_transition_version": 1138407478, + "blocks_root": "4076623c0231898be0722c08e4eb229c44cb957d29cf7370af8a1b9c542d49b3" } } diff --git a/crates/chain-config/src/config/state/writer.rs b/crates/chain-config/src/config/state/writer.rs index a9afec2f2f5..3d96e532410 100644 --- a/crates/chain-config/src/config/state/writer.rs +++ b/crates/chain-config/src/config/state/writer.rs @@ -292,11 +292,13 @@ impl SnapshotWriter { ContractsState, Messages, }; + use fuel_core_types::fuel_vm::BlobData; use crate::AsTable; self.write::(state_config.as_table())?; self.write::(state_config.as_table())?; + self.write::(state_config.as_table())?; self.write::(state_config.as_table())?; self.write::(state_config.as_table())?; self.write::(state_config.as_table())?; diff --git a/crates/client/assets/schema.sdl b/crates/client/assets/schema.sdl index e096eb04301..4fcf0540926 100644 --- a/crates/client/assets/schema.sdl +++ b/crates/client/assets/schema.sdl @@ -44,6 +44,8 @@ input BalanceFilterInput { owner: Address! } +scalar BlobId + type Block { version: BlockVersion! id: BlockId! @@ -430,12 +432,15 @@ type GasCosts { xor: U64! xori: U64! alocDependentCost: DependentCost! + bldd: DependentCost + bsiz: DependentCost cfe: DependentCost! cfeiDependentCost: DependentCost! call: DependentCost! ccp: DependentCost! croo: DependentCost! csiz: DependentCost! + ed19DependentCost: DependentCost! k256: DependentCost! ldc: DependentCost! logd: DependentCost! @@ -1143,6 +1148,7 @@ type Transaction { isMint: Boolean! isUpgrade: Boolean! isUpload: Boolean! + isBlob: Boolean! inputs: [Input!] outputs: [Output!]! outputContract: ContractOutput @@ -1152,6 +1158,7 @@ type Transaction { script: HexString scriptData: HexString bytecodeWitnessIndex: U16 + blobId: BlobId salt: Salt storageSlots: [HexString!] bytecodeRoot: Bytes32 diff --git a/crates/client/src/client/schema/chain.rs b/crates/client/src/client/schema/chain.rs index ea6ec9a9972..4c0b3969a14 100644 --- a/crates/client/src/client/schema/chain.rs +++ b/crates/client/src/client/schema/chain.rs @@ -285,12 +285,15 @@ pub struct GasCosts { pub xori: U64, pub aloc_dependent_cost: DependentCost, + pub bsiz: Option, + pub bldd: Option, pub cfe: DependentCost, pub cfei_dependent_cost: DependentCost, pub call: DependentCost, pub ccp: DependentCost, pub croo: DependentCost, pub csiz: DependentCost, + pub ed19_dependent_cost: DependentCost, pub k256: DependentCost, pub ldc: DependentCost, pub logd: DependentCost, @@ -324,8 +327,8 @@ impl TryFrom for fuel_core_types::fuel_tx::GasCosts { fn try_from(value: GasCosts) -> Result { match value.version { - GasCostsVersion::V1 => { - let values = fuel_core_types::fuel_tx::consensus_parameters::gas::GasCostsValuesV3 { + GasCostsVersion::V1 => Ok(fuel_core_types::fuel_tx::GasCosts::new( + fuel_core_types::fuel_tx::consensus_parameters::gas::GasCostsValuesV4 { add: value.add.into(), addi: value.addi.into(), and: value.and.into(), @@ -334,13 +337,14 @@ impl TryFrom for fuel_core_types::fuel_tx::GasCosts { bhei: value.bhei.into(), bhsh: value.bhsh.into(), burn: value.burn.into(), + bldd: value.bldd.unwrap().into(), + bsiz: value.bsiz.unwrap().into(), cb: value.cb.into(), cfsi: value.cfsi.into(), div: value.div.into(), divi: value.divi.into(), eck1: value.eck1.into(), ecr1: value.ecr1.into(), - ed19: value.ed19.into(), eq: value.eq.into(), exp: value.exp.into(), expi: value.expi.into(), @@ -420,6 +424,7 @@ impl TryFrom for fuel_core_types::fuel_tx::GasCosts { ccp: value.ccp.into(), croo: value.croo.into(), csiz: value.csiz.into(), + ed19: value.ed19_dependent_cost.into(), k256: value.k256.into(), ldc: value.ldc.into(), logd: value.logd.into(), @@ -438,9 +443,9 @@ impl TryFrom for fuel_core_types::fuel_tx::GasCosts { state_root: value.state_root.into(), vm_initialization: value.vm_initialization.into(), new_storage_per_byte: value.new_storage_per_byte.into(), - }; - Ok(fuel_core_types::fuel_tx::GasCosts::new(values.into())) - } + } + .into(), + )), } } } diff --git a/crates/client/src/client/schema/primitives.rs b/crates/client/src/client/schema/primitives.rs index db1b34b3e45..1559c835844 100644 --- a/crates/client/src/client/schema/primitives.rs +++ b/crates/client/src/client/schema/primitives.rs @@ -109,6 +109,7 @@ fuel_type_scalar!(Bytes32, Bytes32); fuel_type_scalar!(Address, Address); fuel_type_scalar!(BlockId, Bytes32); fuel_type_scalar!(AssetId, AssetId); +fuel_type_scalar!(BlobId, BlobId); fuel_type_scalar!(ContractId, ContractId); fuel_type_scalar!(Salt, Salt); fuel_type_scalar!(TransactionId, Bytes32); 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 6197468df8d..50746c31bd6 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 @@ -175,6 +175,28 @@ query { gasPerUnit } } + bsiz { + __typename + ... on LightOperation { + base + unitsPerGas + } + ... on HeavyOperation { + base + gasPerUnit + } + } + bldd { + __typename + ... on LightOperation { + base + unitsPerGas + } + ... on HeavyOperation { + base + gasPerUnit + } + } cfe { __typename ... on LightOperation { @@ -241,6 +263,17 @@ query { gasPerUnit } } + ed19DependentCost { + __typename + ... on LightOperation { + base + unitsPerGas + } + ... on HeavyOperation { + base + gasPerUnit + } + } k256 { __typename ... on LightOperation { diff --git a/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__tx__tests__transparent_transaction_by_id_query_gql_output.snap b/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__tx__tests__transparent_transaction_by_id_query_gql_output.snap index b4b4094c67e..a561351068a 100644 --- a/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__tx__tests__transparent_transaction_by_id_query_gql_output.snap +++ b/crates/client/src/client/schema/snapshots/fuel_core_client__client__schema__tx__tests__transparent_transaction_by_id_query_gql_output.snap @@ -53,6 +53,7 @@ query($id: TransactionId!) { isMint isUpgrade isUpload + isBlob outputs { __typename ... on CoinOutput { @@ -207,5 +208,6 @@ query($id: TransactionId!) { root } } + blobId } } diff --git a/crates/client/src/client/schema/tx/transparent_tx.rs b/crates/client/src/client/schema/tx/transparent_tx.rs index 230630d1c9b..4bce1dd17c8 100644 --- a/crates/client/src/client/schema/tx/transparent_tx.rs +++ b/crates/client/src/client/schema/tx/transparent_tx.rs @@ -6,6 +6,7 @@ use crate::client::schema::{ }, Address, AssetId, + BlobId, Bytes32, ConnectionArgs, ContractId, @@ -26,12 +27,13 @@ use core::convert::{ TryInto, }; use fuel_core_types::{ - fuel_tx, fuel_tx::{ + self, field::ReceiptsRoot, input, output, policies::PolicyType, + BlobBody, StorageSlot, UploadBody, }, @@ -127,6 +129,11 @@ pub struct Transaction { /// The result of a `is_upload()` helper function is stored here. /// It is not an original field of the `Transaction`. pub is_upload: bool, + /// It is `true` for `Transaction::Blob`. + /// + /// The result of a `is_blob()` helper function is stored here. + /// It is not an original field of the `Transaction`. + pub is_blob: bool, /// The field of the `Transaction` type. pub outputs: Vec, /// The field of the `Transaction::Mint`. @@ -165,6 +172,8 @@ pub struct Transaction { pub proof_set: Option>, /// The field of the `Transaction::Upgrade`. pub upgrade_purpose: Option, + /// The field of the `Transaction::Blob`. + pub blob_id: Option, } impl TryFrom for fuel_tx::Transaction { @@ -387,6 +396,43 @@ impl TryFrom for fuel_tx::Transaction { .collect(), ); tx.into() + } else if tx.is_blob { + let tx = fuel_tx::Transaction::blob( + BlobBody { + id: tx + .blob_id + .ok_or_else(|| { + ConversionError::MissingField("blob_id".to_string()) + })? + .into(), + witness_index: tx + .bytecode_witness_index + .ok_or_else(|| { + ConversionError::MissingField("witness_index".to_string()) + })? + .into(), + }, + tx.policies + .ok_or_else(|| ConversionError::MissingField("policies".to_string()))? + .into(), + tx.inputs + .ok_or_else(|| ConversionError::MissingField("inputs".to_string()))? + .into_iter() + .map(TryInto::try_into) + .collect::, ConversionError>>()?, + tx.outputs + .into_iter() + .map(TryInto::try_into) + .collect::, ConversionError>>()?, + tx.witnesses + .ok_or_else(|| { + ConversionError::MissingField("witnesses".to_string()) + })? + .into_iter() + .map(|w| w.0 .0.into()) + .collect(), + ); + tx.into() } else { return Err(ConversionError::UnknownVariant("Transaction")); }; @@ -401,6 +447,7 @@ impl TryFrom for fuel_tx::Transaction { fuel_tx::Transaction::Mint(_) => {} fuel_tx::Transaction::Upgrade(_) => {} fuel_tx::Transaction::Upload(_) => {} + fuel_tx::Transaction::Blob(_) => {} }; Ok(tx) diff --git a/crates/client/src/client/types/gas_costs.rs b/crates/client/src/client/types/gas_costs.rs index 96b90b441dd..1ffadc7be0c 100644 --- a/crates/client/src/client/types/gas_costs.rs +++ b/crates/client/src/client/types/gas_costs.rs @@ -67,10 +67,6 @@ impl GasCosts { self.0.ecr1() } - pub fn ed19(&self) -> Word { - self.0.ed19() - } - pub fn eq_(&self) -> Word { self.0.eq_() } @@ -382,6 +378,10 @@ impl GasCosts { self.0.csiz().into() } + pub fn ed19(&self) -> DependentCost { + self.0.ed19().into() + } + pub fn k256(&self) -> DependentCost { self.0.k256().into() } diff --git a/crates/fuel-core/src/combined_database.rs b/crates/fuel-core/src/combined_database.rs index 3d0aab73d2b..c5134c07272 100644 --- a/crates/fuel-core/src/combined_database.rs +++ b/crates/fuel-core/src/combined_database.rs @@ -182,6 +182,7 @@ impl CombinedDatabase { use fuel_core_chain_config::AddTable; use fuel_core_producer::ports::BlockProducerDatabase; use fuel_core_storage::transactional::AtomicView; + use fuel_core_types::fuel_vm::BlobData; use itertools::Itertools; let mut builder = StateConfigBuilder::default(); @@ -200,6 +201,7 @@ impl CombinedDatabase { add_tables!( Coins, Messages, + BlobData, ContractsAssets, ContractsState, ContractsRawCode, diff --git a/crates/fuel-core/src/graphql_api/worker_service.rs b/crates/fuel-core/src/graphql_api/worker_service.rs index 969c9b879de..6af5ae30ce7 100644 --- a/crates/fuel-core/src/graphql_api/worker_service.rs +++ b/crates/fuel-core/src/graphql_api/worker_service.rs @@ -256,6 +256,10 @@ where inputs = tx.inputs().as_slice(); outputs = tx.outputs().as_slice(); } + Transaction::Blob(tx) => { + inputs = tx.inputs().as_slice(); + outputs = tx.outputs().as_slice(); + } } persist_owners_index( block_height, @@ -373,7 +377,8 @@ where Transaction::Script(_) | Transaction::Mint(_) | Transaction::Upgrade(_) - | Transaction::Upload(_) => { + | Transaction::Upload(_) + | Transaction::Blob(_) => { // Do nothing } } diff --git a/crates/fuel-core/src/schema/chain.rs b/crates/fuel-core/src/schema/chain.rs index cfc364f126d..521bf9c712e 100644 --- a/crates/fuel-core/src/schema/chain.rs +++ b/crates/fuel-core/src/schema/chain.rs @@ -335,9 +335,10 @@ impl FeeParameters { impl GasCosts { async fn version(&self) -> GasCostsVersion { match self.0.deref() { - GasCostsValues::V1(_) | GasCostsValues::V2(_) | GasCostsValues::V3(_) => { - GasCostsVersion::V1 - } + GasCostsValues::V1(_) + | GasCostsValues::V2(_) + | GasCostsValues::V3(_) + | GasCostsValues::V4(_) => GasCostsVersion::V1, } } @@ -406,7 +407,7 @@ impl GasCosts { } async fn ed19(&self) -> U64 { - self.0.ed19().into() + self.0.ed19().base().into() } async fn eq(&self) -> U64 { @@ -697,6 +698,14 @@ impl GasCosts { self.0.aloc().into() } + async fn bldd(&self) -> Option { + self.0.bldd().ok().map(Into::into) + } + + async fn bsiz(&self) -> Option { + self.0.bsiz().ok().map(Into::into) + } + async fn cfe(&self) -> DependentCost { self.0.cfe().into() } @@ -721,6 +730,10 @@ impl GasCosts { self.0.csiz().into() } + async fn ed19_dependent_cost(&self) -> DependentCost { + self.0.ed19().into() + } + async fn k256(&self) -> DependentCost { self.0.k256().into() } diff --git a/crates/fuel-core/src/schema/dap.rs b/crates/fuel-core/src/schema/dap.rs index 6b0139394fc..7e920f3ead2 100644 --- a/crates/fuel-core/src/schema/dap.rs +++ b/crates/fuel-core/src/schema/dap.rs @@ -497,6 +497,9 @@ impl DapMutation { CheckedTransaction::Upload(_) => { Err(async_graphql::Error::new("`Upload` is not supported")) } + CheckedTransaction::Blob(_) => { + Err(async_graphql::Error::new("`Blob` is not supported")) + } } } diff --git a/crates/fuel-core/src/schema/scalars.rs b/crates/fuel-core/src/schema/scalars.rs index f7b51da1009..e75b3271f98 100644 --- a/crates/fuel-core/src/schema/scalars.rs +++ b/crates/fuel-core/src/schema/scalars.rs @@ -295,6 +295,7 @@ fuel_type_scalar!("Bytes32", Bytes32, Bytes32, 32); fuel_type_scalar!("Address", Address, Address, 32); fuel_type_scalar!("BlockId", BlockId, Bytes32, 32); fuel_type_scalar!("AssetId", AssetId, AssetId, 32); +fuel_type_scalar!("BlobId", BlobId, BlobId, 32); fuel_type_scalar!("ContractId", ContractId, ContractId, 32); fuel_type_scalar!("Salt", Salt, Salt, 32); fuel_type_scalar!("TransactionId", TransactionId, Bytes32, 32); diff --git a/crates/fuel-core/src/schema/tx/types.rs b/crates/fuel-core/src/schema/tx/types.rs index 52d3c1dcd37..1b1d94ee8cf 100644 --- a/crates/fuel-core/src/schema/tx/types.rs +++ b/crates/fuel-core/src/schema/tx/types.rs @@ -21,6 +21,7 @@ use crate::{ block::Block, scalars::{ AssetId, + BlobId, Bytes32, ContractId, HexString, @@ -53,6 +54,7 @@ use fuel_core_types::{ field::{ BytecodeRoot, BytecodeWitnessIndex, + ChargeableBody, InputContract, Inputs, Maturity, @@ -86,8 +88,10 @@ use fuel_core_types::{ TransactionExecutionResult, TransactionExecutionStatus, }, - txpool, - txpool::TransactionStatus as TxStatus, + txpool::{ + self, + TransactionStatus as TxStatus, + }, }, tai64::Tai64, }; @@ -426,6 +430,11 @@ impl Transaction { .map(|c| AssetId(*c)) .collect(), ), + fuel_tx::Transaction::Blob(tx) => Some( + tx.input_asset_ids(base_asset_id) + .map(|c| AssetId(*c)) + .collect(), + ), } } @@ -446,6 +455,9 @@ impl Transaction { fuel_tx::Transaction::Upload(tx) => { Some(input_contracts(tx).map(|v| (*v).into()).collect()) } + fuel_tx::Transaction::Blob(tx) => { + Some(input_contracts(tx).map(|v| (*v).into()).collect()) + } } } @@ -454,7 +466,8 @@ impl Transaction { fuel_tx::Transaction::Script(_) | fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Upgrade(_) - | fuel_tx::Transaction::Upload(_) => None, + | fuel_tx::Transaction::Upload(_) + | fuel_tx::Transaction::Blob(_) => None, fuel_tx::Transaction::Mint(mint) => Some(mint.input_contract().into()), } } @@ -466,6 +479,7 @@ impl Transaction { fuel_tx::Transaction::Mint(_) => None, fuel_tx::Transaction::Upgrade(tx) => Some((*tx.policies()).into()), fuel_tx::Transaction::Upload(tx) => Some((*tx.policies()).into()), + fuel_tx::Transaction::Blob(tx) => Some((*tx.policies()).into()), } } @@ -477,7 +491,8 @@ impl Transaction { fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Mint(_) | fuel_tx::Transaction::Upgrade(_) - | fuel_tx::Transaction::Upload(_) => None, + | fuel_tx::Transaction::Upload(_) + | fuel_tx::Transaction::Blob(_) => None, } } @@ -488,6 +503,7 @@ impl Transaction { fuel_tx::Transaction::Mint(_) => None, fuel_tx::Transaction::Upgrade(tx) => Some(tx.maturity().into()), fuel_tx::Transaction::Upload(tx) => Some(tx.maturity().into()), + fuel_tx::Transaction::Blob(tx) => Some(tx.maturity().into()), } } @@ -496,7 +512,8 @@ impl Transaction { fuel_tx::Transaction::Script(_) | fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Upgrade(_) - | fuel_tx::Transaction::Upload(_) => None, + | fuel_tx::Transaction::Upload(_) + | fuel_tx::Transaction::Blob(_) => None, fuel_tx::Transaction::Mint(mint) => Some((*mint.mint_amount()).into()), } } @@ -506,7 +523,8 @@ impl Transaction { fuel_tx::Transaction::Script(_) | fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Upgrade(_) - | fuel_tx::Transaction::Upload(_) => None, + | fuel_tx::Transaction::Upload(_) + | fuel_tx::Transaction::Blob(_) => None, fuel_tx::Transaction::Mint(mint) => Some((*mint.mint_asset_id()).into()), } } @@ -516,7 +534,8 @@ impl Transaction { fuel_tx::Transaction::Script(_) | fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Upgrade(_) - | fuel_tx::Transaction::Upload(_) => None, + | fuel_tx::Transaction::Upload(_) + | fuel_tx::Transaction::Blob(_) => None, fuel_tx::Transaction::Mint(mint) => Some((*mint.gas_price()).into()), } } @@ -527,7 +546,8 @@ impl Transaction { fuel_tx::Transaction::Script(_) | fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Upgrade(_) - | fuel_tx::Transaction::Upload(_) => None, + | fuel_tx::Transaction::Upload(_) + | fuel_tx::Transaction::Blob(_) => None, fuel_tx::Transaction::Mint(mint) => Some((*mint.tx_pointer()).into()), } } @@ -552,6 +572,10 @@ impl Transaction { self.0.is_upload() } + async fn is_blob(&self) -> bool { + self.0.is_blob() + } + async fn inputs(&self) -> Option> { match &self.0 { fuel_tx::Transaction::Script(tx) => { @@ -567,6 +591,9 @@ impl Transaction { fuel_tx::Transaction::Upload(tx) => { Some(tx.inputs().iter().map(Into::into).collect()) } + fuel_tx::Transaction::Blob(tx) => { + Some(tx.inputs().iter().map(Into::into).collect()) + } } } @@ -585,6 +612,9 @@ impl Transaction { fuel_tx::Transaction::Upload(tx) => { tx.outputs().iter().map(Into::into).collect() } + fuel_tx::Transaction::Blob(tx) => { + tx.outputs().iter().map(Into::into).collect() + } } } @@ -593,7 +623,8 @@ impl Transaction { fuel_tx::Transaction::Script(_) | fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Upgrade(_) - | fuel_tx::Transaction::Upload(_) => None, + | fuel_tx::Transaction::Upload(_) + | fuel_tx::Transaction::Blob(_) => None, fuel_tx::Transaction::Mint(mint) => Some(mint.output_contract().into()), } } @@ -625,6 +656,12 @@ impl Transaction { .map(|w| HexString(w.clone().into_inner())) .collect(), ), + fuel_tx::Transaction::Blob(tx) => Some( + tx.witnesses() + .iter() + .map(|w| HexString(w.clone().into_inner())) + .collect(), + ), } } @@ -636,7 +673,8 @@ impl Transaction { fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Mint(_) | fuel_tx::Transaction::Upgrade(_) - | fuel_tx::Transaction::Upload(_) => None, + | fuel_tx::Transaction::Upload(_) + | fuel_tx::Transaction::Blob(_) => None, } } @@ -659,7 +697,8 @@ impl Transaction { fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Mint(_) | fuel_tx::Transaction::Upgrade(_) - | fuel_tx::Transaction::Upload(_) => None, + | fuel_tx::Transaction::Upload(_) + | fuel_tx::Transaction::Blob(_) => None, } } @@ -671,7 +710,8 @@ impl Transaction { fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Mint(_) | fuel_tx::Transaction::Upgrade(_) - | fuel_tx::Transaction::Upload(_) => None, + | fuel_tx::Transaction::Upload(_) + | fuel_tx::Transaction::Blob(_) => None, } } @@ -686,6 +726,14 @@ impl Transaction { fuel_tx::Transaction::Upload(tx) => { Some((*tx.bytecode_witness_index()).into()) } + fuel_tx::Transaction::Blob(tx) => Some((*tx.bytecode_witness_index()).into()), + } + } + + async fn blob_id(&self) -> Option { + match &self.0 { + fuel_tx::Transaction::Blob(blob) => Some(blob.body().id.into()), + _ => None, } } @@ -696,6 +744,7 @@ impl Transaction { fuel_tx::Transaction::Mint(_) => None, fuel_tx::Transaction::Upgrade(_) => None, fuel_tx::Transaction::Upload(_) => None, + fuel_tx::Transaction::Blob(_) => None, } } @@ -721,6 +770,7 @@ impl Transaction { fuel_tx::Transaction::Mint(_) => None, fuel_tx::Transaction::Upgrade(_) => None, fuel_tx::Transaction::Upload(_) => None, + fuel_tx::Transaction::Blob(_) => None, } } @@ -729,7 +779,8 @@ impl Transaction { fuel_tx::Transaction::Script(_) | fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Mint(_) - | fuel_tx::Transaction::Upgrade(_) => None, + | fuel_tx::Transaction::Upgrade(_) + | fuel_tx::Transaction::Blob(_) => None, fuel_tx::Transaction::Upload(tx) => Some((*tx.bytecode_root()).into()), } } @@ -739,7 +790,8 @@ impl Transaction { fuel_tx::Transaction::Script(_) | fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Mint(_) - | fuel_tx::Transaction::Upgrade(_) => None, + | fuel_tx::Transaction::Upgrade(_) + | fuel_tx::Transaction::Blob(_) => None, fuel_tx::Transaction::Upload(tx) => Some((*tx.subsection_index()).into()), } } @@ -749,7 +801,8 @@ impl Transaction { fuel_tx::Transaction::Script(_) | fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Mint(_) - | fuel_tx::Transaction::Upgrade(_) => None, + | fuel_tx::Transaction::Upgrade(_) + | fuel_tx::Transaction::Blob(_) => None, fuel_tx::Transaction::Upload(tx) => Some((*tx.subsections_number()).into()), } } @@ -759,7 +812,8 @@ impl Transaction { fuel_tx::Transaction::Script(_) | fuel_tx::Transaction::Create(_) | fuel_tx::Transaction::Mint(_) - | fuel_tx::Transaction::Upgrade(_) => None, + | fuel_tx::Transaction::Upgrade(_) + | fuel_tx::Transaction::Blob(_) => None, fuel_tx::Transaction::Upload(tx) => { Some(tx.proof_set().iter().map(|proof| (*proof).into()).collect()) } @@ -773,6 +827,7 @@ impl Transaction { | fuel_tx::Transaction::Mint(_) => None, fuel_tx::Transaction::Upgrade(tx) => Some((*tx.upgrade_purpose()).into()), fuel_tx::Transaction::Upload(_) => None, + fuel_tx::Transaction::Blob(_) => None, } } diff --git a/crates/fuel-core/src/service/genesis.rs b/crates/fuel-core/src/service/genesis.rs index 48c79e16bee..a2ba7f211de 100644 --- a/crates/fuel-core/src/service/genesis.rs +++ b/crates/fuel-core/src/service/genesis.rs @@ -261,6 +261,7 @@ mod tests { }, }; use fuel_core_chain_config::{ + BlobConfig, CoinConfig, ContractConfig, LastBlockConfig, @@ -343,6 +344,10 @@ mod tests { .take(1000) .collect_vec(); + let blobs = std::iter::repeat_with(|| BlobConfig::randomize(&mut rng)) + .take(1000) + .collect_vec(); + let contracts = std::iter::repeat_with(|| given_contract_config(&mut rng)) .take(1000) .collect_vec(); @@ -350,6 +355,7 @@ mod tests { let state = StateConfig { coins, messages, + blobs, contracts, last_block: Some(LastBlockConfig { block_height: BlockHeight::from(0u32), diff --git a/crates/fuel-core/src/service/genesis/exporter.rs b/crates/fuel-core/src/service/genesis/exporter.rs index 7f405156d9b..8e7b5ff204c 100644 --- a/crates/fuel-core/src/service/genesis/exporter.rs +++ b/crates/fuel-core/src/service/genesis/exporter.rs @@ -53,7 +53,10 @@ use fuel_core_storage::{ }, transactional::AtomicView, }; -use fuel_core_types::fuel_types::ContractId; +use fuel_core_types::{ + fuel_types::ContractId, + fuel_vm::BlobData, +}; use itertools::Itertools; use super::{ @@ -105,6 +108,7 @@ where |ctx: &Self| ctx.db.on_chain(), Coins, Messages, + BlobData, ContractsRawCode, ContractsLatestUtxo, ContractsState, diff --git a/crates/fuel-core/src/service/genesis/importer.rs b/crates/fuel-core/src/service/genesis/importer.rs index ae90fadc971..bb3d2f94a11 100644 --- a/crates/fuel-core/src/service/genesis/importer.rs +++ b/crates/fuel-core/src/service/genesis/importer.rs @@ -59,6 +59,7 @@ use fuel_core_types::{ primitives::DaBlockHeight, }, fuel_types::BlockHeight, + fuel_vm::BlobData, }; use import_task::{ ImportTable, @@ -112,6 +113,7 @@ impl SnapshotImporter { tracing::info!("Running imports"); self.spawn_worker_on_chain::()?; self.spawn_worker_on_chain::()?; + self.spawn_worker_on_chain::()?; self.spawn_worker_on_chain::()?; self.spawn_worker_on_chain::()?; self.spawn_worker_on_chain::()?; diff --git a/crates/fuel-core/src/service/genesis/importer/on_chain.rs b/crates/fuel-core/src/service/genesis/importer/on_chain.rs index 6f1395b43ee..c5ed0d5cca6 100644 --- a/crates/fuel-core/src/service/genesis/importer/on_chain.rs +++ b/crates/fuel-core/src/service/genesis/importer/on_chain.rs @@ -35,6 +35,7 @@ use fuel_core_types::{ Message, }, fuel_types::BlockHeight, + fuel_vm::BlobData, }; impl ImportTable for Handler { @@ -89,6 +90,22 @@ impl ImportTable for Handler { } } +impl ImportTable for Handler { + type TableInSnapshot = BlobData; + type TableBeingWritten = BlobData; + type DbDesc = OnChain; + + fn process( + &mut self, + group: Vec>, + tx: &mut StorageTransaction<&mut GenesisDatabase>, + ) -> anyhow::Result<()> { + group + .into_iter() + .try_for_each(|entry| init_blob_payload(tx, &entry)) + } +} + impl ImportTable for Handler { type TableInSnapshot = ContractsRawCode; type TableBeingWritten = ContractsRawCode; @@ -253,6 +270,25 @@ fn init_contract_latest_utxo( Ok(()) } +fn init_blob_payload( + transaction: &mut StorageTransaction<&mut GenesisDatabase>, + entry: &TableEntry, +) -> anyhow::Result<()> { + let payload = entry.value.as_ref(); + let blob_id = entry.key; + + // insert blob payload + if transaction + .storage::() + .replace(&blob_id, payload)? + .is_some() + { + return Err(anyhow!("Blob should not exist")); + } + + Ok(()) +} + fn init_contract_raw_code( transaction: &mut StorageTransaction<&mut GenesisDatabase>, entry: &TableEntry, diff --git a/crates/services/executor/src/executor.rs b/crates/services/executor/src/executor.rs index 1f9b5f43076..11589e97122 100644 --- a/crates/services/executor/src/executor.rs +++ b/crates/services/executor/src/executor.rs @@ -921,7 +921,8 @@ where Transaction::Script(_) | Transaction::Create(_) | Transaction::Upgrade(_) - | Transaction::Upload(_) => Ok(()), + | Transaction::Upload(_) + | Transaction::Blob(_) => Ok(()), } } @@ -941,6 +942,7 @@ where } Transaction::Upgrade(tx) => tx.max_gas(gas_costs, fee_params), Transaction::Upload(tx) => tx.max_gas(gas_costs, fee_params), + Transaction::Blob(tx) => tx.max_gas(gas_costs, fee_params), }; if actual_max_gas > claimed_max_gas { return Err(ForcedTransactionFailure::InsufficientMaxGas { @@ -1015,6 +1017,15 @@ where storage_tx, memory, ), + CheckedTransaction::Blob(tx) => self.execute_chargeable_transaction( + tx, + header, + coinbase_contract_id, + gas_price, + execution_data, + storage_tx, + memory, + ), } } diff --git a/crates/services/executor/src/ports.rs b/crates/services/executor/src/ports.rs index 29ac0d07302..7f978bd43fe 100644 --- a/crates/services/executor/src/ports.rs +++ b/crates/services/executor/src/ports.rs @@ -42,6 +42,10 @@ impl MaybeCheckedTransaction { CheckedTransaction::Upload(tx), _, ) => tx.id(), + MaybeCheckedTransaction::CheckedTransaction( + CheckedTransaction::Blob(tx), + _, + ) => tx.id(), MaybeCheckedTransaction::Transaction(tx) => tx.id(chain_id), } } diff --git a/crates/services/txpool/src/txpool.rs b/crates/services/txpool/src/txpool.rs index 9bed5bb4645..11aef526b2e 100644 --- a/crates/services/txpool/src/txpool.rs +++ b/crates/services/txpool/src/txpool.rs @@ -363,6 +363,7 @@ where CheckedTransaction::Mint(_) => return Err(Error::MintIsDisallowed), CheckedTransaction::Upgrade(tx) => PoolTransaction::Upgrade(tx, version), CheckedTransaction::Upload(tx) => PoolTransaction::Upload(tx, version), + CheckedTransaction::Blob(tx) => PoolTransaction::Blob(tx, version), }); self.check_blacklisting(tx.as_ref())?; @@ -571,6 +572,11 @@ fn verify_tx_min_gas_price( let (_, checked) = ready.decompose(); CheckedTransaction::Upload(checked) } + CheckedTransaction::Blob(tx) => { + let ready = tx.into_ready(gas_price, gas_costs, fee_parameters)?; + let (_, checked) = ready.decompose(); + CheckedTransaction::Blob(checked) + } CheckedTransaction::Mint(_) => return Err(Error::MintIsDisallowed), }; Ok(read.into()) diff --git a/crates/storage/src/column.rs b/crates/storage/src/column.rs index 1f1592dd9f0..1556fa38595 100644 --- a/crates/storage/src/column.rs +++ b/crates/storage/src/column.rs @@ -59,10 +59,12 @@ pub enum Column { StateTransitionBytecodeVersions = 18, /// See [`UploadedBytecodes`](crate::tables::UploadedBytecodes) UploadedBytecodes = 19, + /// See [`Blobs`](fuel_vm_private::storage::BlobData) + Blobs = 20, // TODO: Remove this column and use `Metadata` column instead. /// Table for genesis state import progress tracking. - GenesisMetadata = 20, + GenesisMetadata = 21, } impl Column { diff --git a/crates/storage/src/structured_storage.rs b/crates/storage/src/structured_storage.rs index 04076899e3a..8b5c5094e88 100644 --- a/crates/storage/src/structured_storage.rs +++ b/crates/storage/src/structured_storage.rs @@ -49,6 +49,7 @@ use std::{ }; pub mod balances; +pub mod blobs; pub mod blocks; pub mod coins; pub mod contracts; diff --git a/crates/storage/src/structured_storage/blobs.rs b/crates/storage/src/structured_storage/blobs.rs new file mode 100644 index 00000000000..ed1cba4f7de --- /dev/null +++ b/crates/storage/src/structured_storage/blobs.rs @@ -0,0 +1,31 @@ +//! The module contains implementations and tests for the contracts tables. + +use fuel_vm_private::storage::BlobData; + +use crate::{ + blueprint::plain::Plain, + codec::raw::Raw, + column::Column, + structured_storage::TableWithBlueprint, +}; + +impl TableWithBlueprint for BlobData { + type Blueprint = Plain; + type Column = Column; + + fn column() -> Self::Column { + Column::Blobs + } +} + +#[cfg(test)] +mod test { + use super::*; + + crate::basic_storage_tests!( + BlobData, + ::Key::default(), + vec![32u8], + ::OwnedValue::from(vec![32u8]) + ); +} diff --git a/crates/storage/src/vm_storage.rs b/crates/storage/src/vm_storage.rs index 666b565743c..c2765e8d421 100644 --- a/crates/storage/src/vm_storage.rs +++ b/crates/storage/src/vm_storage.rs @@ -51,6 +51,7 @@ use fuel_core_types::{ use fuel_vm_private::{ fuel_storage::StorageWrite, storage::{ + BlobData, ContractsStateData, UploadedBytecodes, }, @@ -237,6 +238,9 @@ where + StorageMutate + StorageMutate + StorageMutate + + StorageWrite + + StorageSize + + StorageRead + VmStorageRequirements, { type DataError = StorageError; diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs index 7ee96478e45..3b6541db555 100644 --- a/crates/types/src/lib.rs +++ b/crates/types/src/lib.rs @@ -60,6 +60,10 @@ pub mod fuel_vm { storage::ContractsAssetKey, storage::ContractsStateKey, storage::UploadedBytecode, + storage::{ + BlobBytes, + BlobData, + }, util, }; } diff --git a/crates/types/src/services/txpool.rs b/crates/types/src/services/txpool.rs index 7699c744f11..050d1591f0b 100644 --- a/crates/types/src/services/txpool.rs +++ b/crates/types/src/services/txpool.rs @@ -13,6 +13,7 @@ use crate::{ ScriptGasLimit, Tip, }, + Blob, Cacheable, Chargeable, Create, @@ -67,6 +68,8 @@ pub enum PoolTransaction { Upgrade(Checked, ConsensusParametersVersion), /// Upload Upload(Checked, ConsensusParametersVersion), + /// Blob + Blob(Checked, ConsensusParametersVersion), } impl PoolTransaction { @@ -76,7 +79,8 @@ impl PoolTransaction { PoolTransaction::Script(_, version) | PoolTransaction::Create(_, version) | PoolTransaction::Upgrade(_, version) - | PoolTransaction::Upload(_, version) => *version, + | PoolTransaction::Upload(_, version) + | PoolTransaction::Blob(_, version) => *version, } } @@ -87,6 +91,7 @@ impl PoolTransaction { PoolTransaction::Create(tx, _) => tx.transaction().metered_bytes_size(), PoolTransaction::Upgrade(tx, _) => tx.transaction().metered_bytes_size(), PoolTransaction::Upload(tx, _) => tx.transaction().metered_bytes_size(), + PoolTransaction::Blob(tx, _) => tx.transaction().metered_bytes_size(), } } @@ -97,6 +102,7 @@ impl PoolTransaction { PoolTransaction::Create(tx, _) => tx.id(), PoolTransaction::Upgrade(tx, _) => tx.id(), PoolTransaction::Upload(tx, _) => tx.id(), + PoolTransaction::Blob(tx, _) => tx.id(), } } @@ -107,6 +113,7 @@ impl PoolTransaction { PoolTransaction::Create(tx, _) => tx.metadata().max_gas, PoolTransaction::Upgrade(tx, _) => tx.metadata().max_gas, PoolTransaction::Upload(tx, _) => tx.metadata().max_gas, + PoolTransaction::Blob(tx, _) => tx.metadata().max_gas, } } } @@ -121,6 +128,7 @@ impl PoolTransaction { PoolTransaction::Create(_, _) => None, PoolTransaction::Upgrade(_, _) => None, PoolTransaction::Upload(_, _) => None, + PoolTransaction::Blob(_, _) => None, } } @@ -130,6 +138,7 @@ impl PoolTransaction { Self::Create(tx, _) => tx.transaction().tip(), Self::Upload(tx, _) => tx.transaction().tip(), Self::Upgrade(tx, _) => tx.transaction().tip(), + Self::Blob(tx, _) => tx.transaction().tip(), } } @@ -139,6 +148,7 @@ impl PoolTransaction { PoolTransaction::Create(tx, _) => tx.transaction().is_computed(), PoolTransaction::Upgrade(tx, _) => tx.transaction().is_computed(), PoolTransaction::Upload(tx, _) => tx.transaction().is_computed(), + PoolTransaction::Blob(tx, _) => tx.transaction().is_computed(), } } @@ -148,6 +158,7 @@ impl PoolTransaction { PoolTransaction::Create(tx, _) => tx.transaction().inputs(), PoolTransaction::Upgrade(tx, _) => tx.transaction().inputs(), PoolTransaction::Upload(tx, _) => tx.transaction().inputs(), + PoolTransaction::Blob(tx, _) => tx.transaction().inputs(), } } @@ -157,6 +168,7 @@ impl PoolTransaction { PoolTransaction::Create(tx, _) => tx.transaction().outputs(), PoolTransaction::Upgrade(tx, _) => tx.transaction().outputs(), PoolTransaction::Upload(tx, _) => tx.transaction().outputs(), + PoolTransaction::Blob(tx, _) => tx.transaction().outputs(), } } } @@ -176,6 +188,7 @@ impl From<&PoolTransaction> for Transaction { PoolTransaction::Upload(tx, _) => { Transaction::Upload(tx.transaction().clone()) } + PoolTransaction::Blob(tx, _) => Transaction::Blob(tx.transaction().clone()), } } } @@ -187,6 +200,7 @@ impl From<&PoolTransaction> for CheckedTransaction { PoolTransaction::Create(tx, _) => CheckedTransaction::Create(tx.clone()), PoolTransaction::Upgrade(tx, _) => CheckedTransaction::Upgrade(tx.clone()), PoolTransaction::Upload(tx, _) => CheckedTransaction::Upload(tx.clone()), + PoolTransaction::Blob(tx, _) => CheckedTransaction::Blob(tx.clone()), } } } diff --git a/tests/tests/blob.rs b/tests/tests/blob.rs new file mode 100644 index 00000000000..cdbc76296c1 --- /dev/null +++ b/tests/tests/blob.rs @@ -0,0 +1,148 @@ +#![allow(non_snake_case)] + +use fuel_core::{ + database::{ + database_description::on_chain::OnChain, + Database, + }, + service::Config, +}; +use fuel_core_bin::FuelService; +use fuel_core_client::client::{ + types::TransactionStatus, + FuelClient, +}; +use fuel_core_types::{ + fuel_asm::{ + op, + GTFArgs, + RegId, + }, + fuel_tx::{ + BlobBody, + BlobId, + BlobIdExt, + TransactionBuilder, + }, + fuel_types::canonical::Serialize, + fuel_vm::checked_transaction::IntoChecked, +}; + +struct TestContext { + _node: FuelService, + client: FuelClient, +} +impl TestContext { + async fn new() -> Self { + let config = Config { + debug: true, + utxo_validation: false, + ..Config::local_node() + }; + + let _node = FuelService::from_database(Database::::in_memory(), config) + .await + .unwrap(); + let client = FuelClient::from(_node.bound_address); + + Self { _node, client } + } + + async fn new_blob(&mut self, blob_data: Vec) -> (TransactionStatus, BlobId) { + let blob_id = BlobId::compute(&blob_data); + let tx = TransactionBuilder::blob(BlobBody { + id: blob_id, + witness_index: 0, + }) + .add_witness(blob_data.into()) + .add_random_fee_input() + .finalize_as_transaction() + .into_checked(Default::default(), &Default::default()) + .expect("Cannot check transaction"); + + let status = self + .client + .submit_and_await_commit(tx.transaction()) + .await + .expect("Cannot submit blob"); + (status, blob_id) + } +} + +#[tokio::test] +async fn blob__upload_works() { + // Given + let mut ctx = TestContext::new().await; + + // When + let (status, blob_id) = ctx + .new_blob([op::ret(RegId::ONE)].into_iter().collect()) + .await; + assert!(matches!(status, TransactionStatus::Success { .. })); + + // Then + let script_tx = TransactionBuilder::script( + vec![ + op::gtf_args(0x11, RegId::ZERO, GTFArgs::ScriptData), + op::bsiz(0x20, 0x11), // This panics if blob doesn't exist + op::ret(RegId::ONE), + ] + .into_iter() + .collect(), + blob_id.to_bytes(), + ) + .script_gas_limit(1000000) + .add_random_fee_input() + .finalize_as_transaction(); + let tx_status = ctx + .client + .submit_and_await_commit(&script_tx) + .await + .unwrap(); + assert!(matches!(tx_status, TransactionStatus::Success { .. })); +} + +#[tokio::test] +async fn blob__cannot_post_already_existing_blob() { + // Given + let mut ctx = TestContext::new().await; + let payload: Vec = [op::ret(RegId::ONE)].into_iter().collect(); + let (status, _blob_id) = ctx.new_blob(payload.clone()).await; + assert!(matches!(status, TransactionStatus::Success { .. })); + + // When + let (status, _blob_id) = ctx.new_blob(payload).await; + + // Then + assert!(matches!(status, TransactionStatus::SqueezedOut { .. })); +} + +#[tokio::test] +async fn blob__accessing_nonexitent_blob_panics_vm() { + // Given + let ctx = TestContext::new().await; + let blob_id = BlobId::new([0; 32]); // Nonexistent + + // When + let script_tx = TransactionBuilder::script( + vec![ + op::gtf_args(0x11, RegId::ZERO, GTFArgs::ScriptData), + op::bsiz(0x20, 0x11), // This panics if blob doesn't exist + op::ret(RegId::ONE), + ] + .into_iter() + .collect(), + blob_id.to_bytes(), + ) + .script_gas_limit(1000000) + .add_random_fee_input() + .finalize_as_transaction(); + let tx_status = ctx + .client + .submit_and_await_commit(&script_tx) + .await + .unwrap(); + + // Then + assert!(matches!(tx_status, TransactionStatus::Failure { .. })); +} diff --git a/tests/tests/lib.rs b/tests/tests/lib.rs index 96a3eb56d65..e7a3db5bce9 100644 --- a/tests/tests/lib.rs +++ b/tests/tests/lib.rs @@ -2,6 +2,7 @@ #![deny(warnings)] mod balances; +mod blob; mod blocks; mod chain; mod coin; diff --git a/tests/tests/local_node.rs b/tests/tests/local_node.rs index c8fe454f0ae..dd837ab1f26 100644 --- a/tests/tests/local_node.rs +++ b/tests/tests/local_node.rs @@ -52,8 +52,9 @@ fn local_chainconfig_validity() -> anyhow::Result<()> { let stored_chain_config = std::fs::read_to_string(stored_snapshot.chain_config)? .trim() .to_string(); - assert_eq!( - chain_config, stored_chain_config, + pretty_assertions::assert_str_eq!( + chain_config, + stored_chain_config, "Chain config should match the one in the local configuration" ); @@ -75,8 +76,9 @@ fn local_chainconfig_validity() -> anyhow::Result<()> { }; std::fs::read_to_string(generated_state)?.trim().to_string() }; - assert_eq!( - stored_state_config, generated_state_config, + pretty_assertions::assert_str_eq!( + stored_state_config, + generated_state_config, "State config should match the one in the local configuration" ); diff --git a/tests/tests/regenesis.rs b/tests/tests/regenesis.rs index 438f4e8ca9a..993af12cd54 100644 --- a/tests/tests/regenesis.rs +++ b/tests/tests/regenesis.rs @@ -56,7 +56,14 @@ async fn produce_block_with_tx(rng: &mut StdRng, client: &FuelClient) { Default::default(), )) .finalize_as_transaction(); - client.submit_and_await_commit(&contract_tx).await.unwrap(); + let status = client + .submit_and_await_commit(&contract_tx) + .await + .expect("Failed to send tx"); + assert!( + matches!(status, TransactionStatus::Success { .. }), + "{status:?}" + ); } async fn take_snapshot(db_dir: &TempDir, snapshot_dir: &TempDir) -> anyhow::Result<()> { @@ -338,7 +345,10 @@ async fn test_regenesis_processed_transactions_are_preserved() -> anyhow::Result else { panic!("Expected transaction to be squeezed out") }; - assert!(reason.contains("Transaction id was already used")); + assert!( + reason.contains("Transaction id was already used"), + "Unexpected message {reason:?}" + ); Ok(()) }