From dec09dbdf73f440819aa33f68953e054623c7416 Mon Sep 17 00:00:00 2001 From: Kim Altintop Date: Wed, 31 Jul 2024 10:15:50 +0200 Subject: [PATCH 1/4] core: Use `Program` instead of `(Hash, Box<[u8]>)` Refactor to use `Program` (introduced in #1532) throughout. Also avoid cloning the program bytes to instantiate a wasm module. This makes the `AnyBytes` type unused, so remove it. --- .../locking_tx_datastore/datastore.rs | 14 +-- crates/core/src/db/datastore/traits.rs | 33 ++++-- crates/core/src/db/relational_db.rs | 33 ++---- crates/core/src/host/host_controller.rs | 107 ++++++++++-------- crates/core/src/host/module_host.rs | 55 +++------ .../src/host/wasm_common/module_host_actor.rs | 26 ++--- crates/core/src/host/wasmtime/mod.rs | 2 +- crates/core/src/module_host_context.rs | 9 +- crates/core/src/util/mod.rs | 35 ------ 9 files changed, 124 insertions(+), 190 deletions(-) diff --git a/crates/core/src/db/datastore/locking_tx_datastore/datastore.rs b/crates/core/src/db/datastore/locking_tx_datastore/datastore.rs index 1e5cc526520..6559fdcc02d 100644 --- a/crates/core/src/db/datastore/locking_tx_datastore/datastore.rs +++ b/crates/core/src/db/datastore/locking_tx_datastore/datastore.rs @@ -34,7 +34,7 @@ use spacetimedb_lib::db::{ }; use spacetimedb_lib::{Address, Identity}; use spacetimedb_primitives::{ColList, ConstraintId, IndexId, SequenceId, TableId}; -use spacetimedb_sats::{bsatn, buffer::BufReader, hash::Hash, AlgebraicValue, ProductValue}; +use spacetimedb_sats::{bsatn, buffer::BufReader, AlgebraicValue, ProductValue}; use spacetimedb_schema::schema::TableSchema; use spacetimedb_snapshot::ReconstructedSnapshot; use spacetimedb_table::{ @@ -527,13 +527,7 @@ impl MutTxDatastore for Locking { tx.iter(&ctx, ST_MODULE_ID)?.next().map(metadata_from_row).transpose() } - fn update_program( - &self, - tx: &mut Self::MutTx, - program_kind: ModuleKind, - program_hash: Hash, - program_bytes: Box<[u8]>, - ) -> Result<()> { + fn update_program(&self, tx: &mut Self::MutTx, program_kind: ModuleKind, program: Program) -> Result<()> { let ctx = ExecutionContext::internal(self.database_address); let old = tx .iter(&ctx, ST_MODULE_ID)? @@ -547,8 +541,8 @@ impl MutTxDatastore for Locking { match old { Some((ptr, mut row)) => { row.program_kind = program_kind; - row.program_hash = program_hash; - row.program_bytes = program_bytes; + row.program_hash = program.hash; + row.program_bytes = program.bytes; tx.delete(ST_MODULE_ID, ptr)?; tx.insert(ST_MODULE_ID, &mut row.into(), self.database_address) diff --git a/crates/core/src/db/datastore/traits.rs b/crates/core/src/db/datastore/traits.rs index aca6dbae73e..7623bf227eb 100644 --- a/crates/core/src/db/datastore/traits.rs +++ b/crates/core/src/db/datastore/traits.rs @@ -9,7 +9,7 @@ use crate::db::datastore::system_tables::ST_TABLE_ID; use crate::execution_context::ExecutionContext; use spacetimedb_data_structures::map::IntMap; use spacetimedb_lib::db::raw_def::*; -use spacetimedb_lib::{Address, Identity}; +use spacetimedb_lib::{hash_bytes, Address, Identity}; use spacetimedb_primitives::*; use spacetimedb_sats::hash::Hash; use spacetimedb_sats::{AlgebraicValue, ProductType, ProductValue}; @@ -315,6 +315,7 @@ pub struct Metadata { } /// Program associated with a database. +#[derive(Clone)] pub struct Program { /// Hash over the program's bytes. pub hash: Hash, @@ -322,6 +323,26 @@ pub struct Program { pub bytes: Box<[u8]>, } +impl Program { + /// Create a [`Program`] from its raw bytes. + /// + /// This computes the hash over `bytes`, so prefer constructing [`Program`] + /// directly if the hash is already known. + pub fn from_bytes(bytes: impl Into>) -> Self { + let bytes = bytes.into(); + let hash = hash_bytes(&bytes); + Self { hash, bytes } + } + + /// Create a [`Program`] with no bytes. + pub fn empty() -> Self { + Self { + hash: Hash::ZERO, + bytes: [].into(), + } + } +} + pub trait TxDatastore: DataRow + Tx { type Iter<'a>: Iterator> where @@ -479,15 +500,7 @@ pub trait MutTxDatastore: TxDatastore + MutTx { fn metadata_mut_tx(&self, tx: &Self::MutTx) -> Result>; /// Update the datastore with the supplied binary program. - /// - /// The `program_hash` is the precomputed hash over `program_bytes`. - fn update_program( - &self, - tx: &mut Self::MutTx, - program_kind: ModuleKind, - program_hash: Hash, - program_bytes: Box<[u8]>, - ) -> Result<()>; + fn update_program(&self, tx: &mut Self::MutTx, program_kind: ModuleKind, program: Program) -> Result<()>; } #[cfg(test)] diff --git a/crates/core/src/db/relational_db.rs b/crates/core/src/db/relational_db.rs index bf603b7b216..420c89d16eb 100644 --- a/crates/core/src/db/relational_db.rs +++ b/crates/core/src/db/relational_db.rs @@ -30,7 +30,6 @@ use spacetimedb_lib::db::auth::{StAccess, StTableType}; use spacetimedb_lib::db::raw_def::{RawColumnDefV8, RawIndexDefV8, RawSequenceDefV8, RawTableDefV8}; use spacetimedb_lib::Identity; use spacetimedb_primitives::*; -use spacetimedb_sats::hash::Hash; use spacetimedb_sats::{AlgebraicType, AlgebraicValue, ProductType, ProductValue}; use spacetimedb_schema::schema::TableSchema; use spacetimedb_snapshot::{SnapshotError, SnapshotRepository}; @@ -330,24 +329,18 @@ impl RelationalDB { /// It is an error to call this method on an alread-initialized database. /// /// See [`Self::open`] for further information. - pub fn set_initialized( - &self, - tx: &mut MutTx, - host_type: HostType, - program_hash: Hash, - program_bytes: Box<[u8]>, - ) -> Result<(), DBError> { + pub fn set_initialized(&self, tx: &mut MutTx, host_type: HostType, program: Program) -> Result<(), DBError> { log::trace!( "[{}] DATABASE: set initialized owner={} program_hash={}", self.address, self.owner_identity, - program_hash + program.hash ); // Probably a bug: the database is already initialized. // Ignore if it would be a no-op. if let Some(meta) = self.inner.metadata_mut_tx(tx)? { - if program_hash == meta.program_hash + if program.hash == meta.program_hash && self.address == meta.database_address && self.owner_identity == meta.owner_identity { @@ -362,8 +355,8 @@ impl RelationalDB { program_kind: match host_type { HostType::Wasm => WASM_MODULE, }, - program_hash, - program_bytes, + program_hash: program.hash, + program_bytes: program.bytes, }; self.insert(tx, ST_MODULE_ID, row.into()).map(drop) } @@ -395,23 +388,17 @@ impl RelationalDB { /// /// The caller must ensure that: /// - /// - `program_hash` is the [`Hash`] over `program_bytes`. - /// - `program_bytes` is a valid module acc. to `host_type`. + /// - `program.hash` is the [`Hash`] over `program.bytes`. + /// - `program.bytes` is a valid module acc. to `host_type`. /// - the schema updates contained in the module have been applied within /// the transactional context `tx`. /// - the `__init__` reducer contained in the module has been executed /// within the transactional context `tx`. - pub fn update_program( - &self, - tx: &mut MutTx, - host_type: HostType, - program_hash: Hash, - program_bytes: Box<[u8]>, - ) -> Result<(), DBError> { + pub fn update_program(&self, tx: &mut MutTx, host_type: HostType, program: Program) -> Result<(), DBError> { let program_kind = match host_type { HostType::Wasm => WASM_MODULE, }; - self.inner.update_program(tx, program_kind, program_hash, program_bytes) + self.inner.update_program(tx, program_kind, program) } fn restore_from_snapshot_or_bootstrap( @@ -1427,7 +1414,7 @@ pub mod tests_utils { debug_assert!(connected_clients.is_empty()); let db = db.with_row_count(Self::row_count_fn()); db.with_auto_commit(&ExecutionContext::internal(db.address()), |tx| { - db.set_initialized(tx, HostType::Wasm, Hash::ZERO, [].into()) + db.set_initialized(tx, HostType::Wasm, Program::empty()) })?; Ok(db) } diff --git a/crates/core/src/host/host_controller.rs b/crates/core/src/host/host_controller.rs index 265ca12ff90..9c2f8e0edc5 100644 --- a/crates/core/src/host/host_controller.rs +++ b/crates/core/src/host/host_controller.rs @@ -390,16 +390,9 @@ impl HostController { "[{}] updating database from `{}` to `{}`", db_addr, stored_hash, program_hash ); - let program_bytes = load_program(&self.program_storage, program_hash).await?; + let program = load_program(&self.program_storage, program_hash).await?; let update_result = host - .update_module( - host_type, - Program { - hash: program_hash, - bytes: program_bytes, - }, - self.unregister_fn(instance_id), - ) + .update_module(host_type, program, self.unregister_fn(instance_id)) .await?; if update_result.is_ok() { *guard = Some(host); @@ -523,28 +516,45 @@ async fn make_dbic( async fn make_module_host( host_type: HostType, - mcc: ModuleCreationContext, + dbic: Arc, + scheduler: Scheduler, + program: Program, + energy_monitor: Arc, unregister: impl Fn() + Send + Sync + 'static, -) -> anyhow::Result { +) -> anyhow::Result<(Program, ModuleHost)> { spawn_rayon(move || { let module_host = match host_type { HostType::Wasm => { + let mcc = ModuleCreationContext { + dbic, + scheduler, + program: &program, + energy_monitor, + }; let start = Instant::now(); let actor = host::wasmtime::make_actor(mcc)?; trace!("wasmtime::make_actor blocked for {:?}", start.elapsed()); ModuleHost::new(actor, unregister) } }; - Ok(module_host) + Ok((program, module_host)) }) .await } -async fn load_program(storage: &ProgramStorage, hash: Hash) -> anyhow::Result> { - storage +async fn load_program(storage: &ProgramStorage, hash: Hash) -> anyhow::Result { + let bytes = storage .lookup(hash) .await? - .with_context(|| format!("program {} not found", hash)) + .with_context(|| format!("program {} not found", hash))?; + Ok(Program { hash, bytes }) +} + +struct LaunchedModule { + dbic: Arc, + module_host: ModuleHost, + scheduler: Scheduler, + scheduler_starter: SchedulerStarter, } async fn launch_module( @@ -554,28 +564,33 @@ async fn launch_module( on_panic: impl Fn() + Send + Sync + 'static, relational_db: Arc, energy_monitor: Arc, -) -> anyhow::Result<(Arc, ModuleHost, Scheduler, SchedulerStarter)> { +) -> anyhow::Result<(Program, LaunchedModule)> { let address = database.address; let host_type = database.host_type; let dbic = make_dbic(database, instance_id, relational_db).await.map(Arc::new)?; let (scheduler, scheduler_starter) = Scheduler::open(dbic.relational_db.clone()); - let module_host = make_module_host( + let (program, module_host) = make_module_host( host_type, - ModuleCreationContext { - dbic: dbic.clone(), - scheduler: scheduler.clone(), - program_hash: program.hash, - program_bytes: program.bytes.into(), - energy_monitor: energy_monitor.clone(), - }, + dbic.clone(), + scheduler.clone(), + program, + energy_monitor.clone(), on_panic, ) .await?; trace!("launched database {} with program {}", address, program.hash); - Ok((dbic, module_host, scheduler, scheduler_starter)) + Ok(( + program, + LaunchedModule { + dbic, + module_host, + scheduler, + scheduler_starter, + }, + )) } /// Update a module. @@ -601,7 +616,7 @@ async fn update_module( Ok(()) } else { info!("updating `{}` from {} to {}", addr, stored, program.hash); - module.update_database(program.hash, program.bytes).await? + module.update_database(program).await? }; Ok(res) @@ -677,10 +692,15 @@ impl Host { )? } }; - let (dbic, module_host, scheduler, scheduler_starter) = match db.program()? { + let LaunchedModule { + dbic, + module_host, + scheduler, + scheduler_starter, + } = match db.program()? { // Launch module with program from existing database. Some(program) => { - launch_module( + let (_, launched) = launch_module( database, instance_id, program, @@ -688,34 +708,30 @@ impl Host { Arc::new(db), energy_monitor.clone(), ) - .await? + .await?; + launched } // Database is empty, load program from external storage and run // initialization. None => { - let program_hash = database.initial_program; - let program_bytes = load_program(&program_storage, program_hash).await?; - let res = launch_module( + let program = load_program(&program_storage, database.initial_program).await?; + let (program, launched) = launch_module( database, instance_id, - Program { - hash: program_hash, - bytes: program_bytes.clone(), - }, + program, on_panic, Arc::new(db), energy_monitor.clone(), ) .await?; - let module_host = &res.1; - let call_result = module_host.init_database(program_hash, program_bytes).await?; + let call_result = launched.module_host.init_database(program).await?; if let Some(call_result) = call_result { Result::from(call_result)?; } - res + launched } }; @@ -765,15 +781,12 @@ impl Host { ) -> anyhow::Result { let dbic = &self.dbic; let (scheduler, scheduler_starter) = self.scheduler.new_with_same_db(); - let module = make_module_host( + let (program, module) = make_module_host( host_type, - ModuleCreationContext { - dbic: dbic.clone(), - scheduler: scheduler.clone(), - program_hash: program.hash, - program_bytes: program.bytes.clone().into(), - energy_monitor: self.energy_monitor.clone(), - }, + dbic.clone(), + scheduler.clone(), + program, + self.energy_monitor.clone(), on_panic, ) .await?; diff --git a/crates/core/src/host/module_host.rs b/crates/core/src/host/module_host.rs index 85c4807da85..86957a4e394 100644 --- a/crates/core/src/host/module_host.rs +++ b/crates/core/src/host/module_host.rs @@ -6,7 +6,7 @@ use crate::database_instance_context::DatabaseInstanceContext; use crate::database_logger::{LogLevel, Record}; use crate::db::datastore::locking_tx_datastore::MutTxId; use crate::db::datastore::system_tables::{StClientFields, StClientsRow, ST_CLIENT_ID}; -use crate::db::datastore::traits::{IsolationLevel, TxData}; +use crate::db::datastore::traits::{IsolationLevel, Program, TxData}; use crate::db::update::UpdateDatabaseError; use crate::energy::EnergyQuanta; use crate::error::DBError; @@ -269,14 +269,9 @@ pub trait Module: Send + Sync + 'static { pub trait ModuleInstance: Send + 'static { fn trapped(&self) -> bool; - fn init_database( - &mut self, - program_hash: Hash, - program_bytes: Box<[u8]>, - ) -> anyhow::Result>; + fn init_database(&mut self, program: Program) -> anyhow::Result>; - fn update_database(&mut self, program_hash: Hash, program_bytes: Box<[u8]>) - -> anyhow::Result; + fn update_database(&mut self, program: Program) -> anyhow::Result; fn call_reducer(&mut self, tx: Option, params: CallReducerParams) -> ReducerCallResult; } @@ -311,21 +306,13 @@ impl ModuleInstance for AutoReplacingModuleInstance { fn trapped(&self) -> bool { self.inst.trapped() } - fn init_database( - &mut self, - program_hash: Hash, - program_bytes: Box<[u8]>, - ) -> anyhow::Result> { - let ret = self.inst.init_database(program_hash, program_bytes); + fn init_database(&mut self, program: Program) -> anyhow::Result> { + let ret = self.inst.init_database(program); self.check_trap(); ret } - fn update_database( - &mut self, - program_hash: Hash, - program_bytes: Box<[u8]>, - ) -> anyhow::Result { - let ret = self.inst.update_database(program_hash, program_bytes); + fn update_database(&mut self, program: Program) -> anyhow::Result { + let ret = self.inst.update_database(program); self.check_trap(); ret } @@ -751,28 +738,16 @@ impl ModuleHost { Ok(self.info().log_tx.subscribe()) } - pub async fn init_database( - &self, - program_hash: Hash, - program_bytes: Box<[u8]>, - ) -> Result, InitDatabaseError> { - self.call("", move |inst| { - inst.init_database(program_hash, program_bytes) - }) - .await? - .map_err(InitDatabaseError::Other) + pub async fn init_database(&self, program: Program) -> Result, InitDatabaseError> { + self.call("", move |inst| inst.init_database(program)) + .await? + .map_err(InitDatabaseError::Other) } - pub async fn update_database( - &self, - program_hash: Hash, - program_bytes: Box<[u8]>, - ) -> Result { - self.call("", move |inst| { - inst.update_database(program_hash, program_bytes) - }) - .await? - .map_err(Into::into) + pub async fn update_database(&self, program: Program) -> Result { + self.call("", move |inst| inst.update_database(program)) + .await? + .map_err(Into::into) } pub async fn exit(&self) { diff --git a/crates/core/src/host/wasm_common/module_host_actor.rs b/crates/core/src/host/wasm_common/module_host_actor.rs index 084089d9134..cdfb75e620e 100644 --- a/crates/core/src/host/wasm_common/module_host_actor.rs +++ b/crates/core/src/host/wasm_common/module_host_actor.rs @@ -7,14 +7,13 @@ use std::time::Duration; use spacetimedb_lib::buffer::DecodeError; use spacetimedb_lib::{bsatn, Address, ModuleValidationError, RawModuleDef, RawModuleDefV8, TableDesc}; -use spacetimedb_sats::hash::Hash; use super::instrumentation::CallTimes; use crate::database_instance_context::DatabaseInstanceContext; use crate::database_logger::SystemLogger; use crate::db::datastore::locking_tx_datastore::MutTxId; use crate::db::datastore::system_tables::{StClientsRow, ST_CLIENT_ID}; -use crate::db::datastore::traits::IsolationLevel; +use crate::db::datastore::traits::{IsolationLevel, Program}; use crate::energy::{EnergyMonitor, EnergyQuanta, ReducerBudget, ReducerFingerprint}; use crate::execution_context::{self, ExecutionContext, ReducerContext}; use crate::host::instance_env::InstanceEnv; @@ -133,10 +132,10 @@ impl WasmModuleHostActor { let ModuleCreationContext { dbic: database_instance_context, scheduler, - program_bytes: _, - program_hash: module_hash, + program, energy_monitor, } = mcc; + let module_hash = program.hash; log::trace!( "Making new module host actor for database {} with module {}", database_instance_context.address, @@ -301,11 +300,7 @@ impl ModuleInstance for WasmModuleInstance { } #[tracing::instrument(skip_all, fields(db_id = self.instance.instance_env().dbic.id))] - fn init_database( - &mut self, - program_hash: Hash, - program_bytes: Box<[u8]>, - ) -> anyhow::Result> { + fn init_database(&mut self, program: Program) -> anyhow::Result> { log::debug!("init database"); let timestamp = Timestamp::now(); let stdb = &*self.database_instance_context().relational_db; @@ -321,7 +316,7 @@ impl ModuleInstance for WasmModuleInstance { .with_context(|| format!("failed to create table {table_name}"))?; } - stdb.set_initialized(tx, HostType::Wasm, program_hash, program_bytes)?; + stdb.set_initialized(tx, HostType::Wasm, program)?; anyhow::Ok(()) }) @@ -366,20 +361,15 @@ impl ModuleInstance for WasmModuleInstance { } #[tracing::instrument(skip_all)] - fn update_database( - &mut self, - program_hash: Hash, - program_bytes: Box<[u8]>, - ) -> Result { + fn update_database(&mut self, program: Program) -> Result { let proposed_tables = get_tabledefs(&self.info).collect::>>()?; let stdb = &*self.database_instance_context().relational_db; let ctx = Lazy::new(|| ExecutionContext::internal(stdb.address())); + let program_hash = program.hash; let tx = stdb.begin_mut_tx(IsolationLevel::Serializable); - let (tx, _) = stdb.with_auto_rollback(&ctx, tx, |tx| { - stdb.update_program(tx, HostType::Wasm, program_hash, program_bytes) - })?; + let (tx, _) = stdb.with_auto_rollback(&ctx, tx, |tx| stdb.update_program(tx, HostType::Wasm, program))?; self.system_logger().info(&format!("Updated program to {program_hash}")); let (tx, res) = stdb.with_auto_rollback(&ctx, tx, |tx| { diff --git a/crates/core/src/host/wasmtime/mod.rs b/crates/core/src/host/wasmtime/mod.rs index 8003d8e5b9a..2c8b5b5a645 100644 --- a/crates/core/src/host/wasmtime/mod.rs +++ b/crates/core/src/host/wasmtime/mod.rs @@ -53,7 +53,7 @@ static LINKER: Lazy> = Lazy::new(|| { }); pub fn make_actor(mcc: ModuleCreationContext) -> Result { - let module = Module::new(&ENGINE, &mcc.program_bytes).map_err(ModuleCreationError::WasmCompileError)?; + let module = Module::new(&ENGINE, &mcc.program.bytes).map_err(ModuleCreationError::WasmCompileError)?; let func_imports = module .imports() diff --git a/crates/core/src/module_host_context.rs b/crates/core/src/module_host_context.rs index edbee100622..7ffc08ff816 100644 --- a/crates/core/src/module_host_context.rs +++ b/crates/core/src/module_host_context.rs @@ -1,15 +1,12 @@ -use spacetimedb_lib::Hash; - use crate::database_instance_context::DatabaseInstanceContext; +use crate::db::datastore::traits::Program; use crate::energy::EnergyMonitor; use crate::host::scheduler::Scheduler; -use crate::util::AnyBytes; use std::sync::Arc; -pub struct ModuleCreationContext { +pub struct ModuleCreationContext<'a> { pub dbic: Arc, pub scheduler: Scheduler, - pub program_bytes: AnyBytes, - pub program_hash: Hash, + pub program: &'a Program, pub energy_monitor: Arc, } diff --git a/crates/core/src/util/mod.rs b/crates/core/src/util/mod.rs index 13c8748939d..9906c2955c7 100644 --- a/crates/core/src/util/mod.rs +++ b/crates/core/src/util/mod.rs @@ -1,4 +1,3 @@ -use derive_more::From; use futures::{Future, FutureExt}; use std::borrow::Cow; use std::pin::pin; @@ -18,40 +17,6 @@ pub(crate) fn string_from_utf8_lossy_owned(v: Vec) -> String { } } -#[derive(Clone, From)] -pub enum AnyBytes { - Bytes(bytes::Bytes), - IVec(sled::IVec), -} - -impl From> for AnyBytes { - fn from(b: Vec) -> Self { - Self::Bytes(b.into()) - } -} - -impl From> for AnyBytes { - fn from(b: Box<[u8]>) -> Self { - Self::Bytes(b.into()) - } -} - -impl AsRef<[u8]> for AnyBytes { - fn as_ref(&self) -> &[u8] { - self - } -} - -impl std::ops::Deref for AnyBytes { - type Target = [u8]; - fn deref(&self) -> &Self::Target { - match self { - AnyBytes::Bytes(b) => b, - AnyBytes::IVec(b) => b, - } - } -} - #[track_caller] pub const fn const_unwrap(o: Option) -> T { match o { From 5b6ae613c9949f067c84145c688d211bea01499e Mon Sep 17 00:00:00 2001 From: Kim Altintop Date: Wed, 31 Jul 2024 11:04:10 +0200 Subject: [PATCH 2/4] Update crates/core/src/db/datastore/traits.rs Co-authored-by: Mazdak Farrokhzad Signed-off-by: Kim Altintop --- crates/core/src/db/datastore/traits.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/core/src/db/datastore/traits.rs b/crates/core/src/db/datastore/traits.rs index 7623bf227eb..b943ecc13bd 100644 --- a/crates/core/src/db/datastore/traits.rs +++ b/crates/core/src/db/datastore/traits.rs @@ -315,7 +315,6 @@ pub struct Metadata { } /// Program associated with a database. -#[derive(Clone)] pub struct Program { /// Hash over the program's bytes. pub hash: Hash, From f570038119a8cc519678738774d007460f699dfe Mon Sep 17 00:00:00 2001 From: Kim Altintop Date: Thu, 1 Aug 2024 08:18:52 +0200 Subject: [PATCH 3/4] Update crates/core/src/db/datastore/traits.rs Co-authored-by: Tyler Cloutier Signed-off-by: Kim Altintop --- crates/core/src/db/datastore/traits.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/core/src/db/datastore/traits.rs b/crates/core/src/db/datastore/traits.rs index b943ecc13bd..895048622b9 100644 --- a/crates/core/src/db/datastore/traits.rs +++ b/crates/core/src/db/datastore/traits.rs @@ -336,7 +336,7 @@ impl Program { /// Create a [`Program`] with no bytes. pub fn empty() -> Self { Self { - hash: Hash::ZERO, + hash: hash_bytes([].into()), bytes: [].into(), } } From 4fddc941c841a694bd53fc54de29efafc044ee6f Mon Sep 17 00:00:00 2001 From: Kim Altintop Date: Thu, 1 Aug 2024 08:23:19 +0200 Subject: [PATCH 4/4] fixup! Update crates/core/src/db/datastore/traits.rs --- crates/core/src/db/datastore/traits.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/core/src/db/datastore/traits.rs b/crates/core/src/db/datastore/traits.rs index 895048622b9..1535ec3c9f3 100644 --- a/crates/core/src/db/datastore/traits.rs +++ b/crates/core/src/db/datastore/traits.rs @@ -335,10 +335,7 @@ impl Program { /// Create a [`Program`] with no bytes. pub fn empty() -> Self { - Self { - hash: hash_bytes([].into()), - bytes: [].into(), - } + Self::from_bytes([]) } }