diff --git a/Cargo.lock b/Cargo.lock index 005c9f33..1b49b771 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,7 +8,7 @@ version = "0.11.0-beta.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaa9bf6c54f2d232adc6a9e748f359f1b4570d0a498f92e7823321ae7c656b5" dependencies = [ - "amplify", + "amplify 4.7.0", "ascii-armor", "baid64", "blake3", @@ -40,6 +40,18 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "amplify" +version = "5.0.0-beta.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d41888768802fc62c27b46427127b119e8a16e1f1f59495aced93a340f55eb25" +dependencies = [ + "amplify_derive", + "amplify_num", + "ascii", + "wasm-bindgen", +] + [[package]] name = "amplify_apfloat" version = "0.3.1" @@ -126,7 +138,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4966ac403dc4a666d8131dfe4df684f45acc68d4c7e768db89c463aa5617910" dependencies = [ - "amplify", + "amplify 4.7.0", "baid64", "base85", "sha2", @@ -145,7 +157,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95dabc2759e01e2c382968639868a701f384a18890934f9e75d4feb4d6623794" dependencies = [ - "amplify", + "amplify 4.7.0", "base64", "mnemonic", "sha2", @@ -218,7 +230,7 @@ version = "0.11.0-beta.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d23ea438647522d1f1a8fc8fa1420cc56321433d5d5964636294991f18f9e0c9" dependencies = [ - "amplify", + "amplify 4.7.0", "chrono", "commit_verify", "secp256k1", @@ -233,7 +245,7 @@ version = "0.11.0-beta.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b43a6b5389fd99298fca47f4566dda754fa10bdb41200b5cdfc16147400f5951" dependencies = [ - "amplify", + "amplify 4.7.0", "bp-consensus", "bp-dbc", "bp-seals", @@ -252,7 +264,7 @@ version = "0.11.0-beta.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f70bd407dfcbeadfbc012959e04decbe63e7dc6f30a4f705b804b699b37a0a" dependencies = [ - "amplify", + "amplify 4.7.0", "base85", "bp-consensus", "commit_verify", @@ -267,7 +279,7 @@ version = "0.11.0-beta.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddcb55fe081418fc6e508370eaf8431001274727862e57e6672b6c892b8d3d66" dependencies = [ - "amplify", + "amplify 4.7.0", "bech32", "bp-consensus", "commit_verify", @@ -279,7 +291,7 @@ version = "0.11.0-beta.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497bb5989b9b549cd8e4ebfabc50a5d57cf318ab56affd3d4d7b7749fcd780da" dependencies = [ - "amplify", + "amplify 4.7.0", "baid64", "bp-consensus", "bp-dbc", @@ -338,7 +350,7 @@ version = "0.11.0-beta.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca41bd14a6c400486463a5b0e7e8916b1c7bad554a382f62c3b11bd58dea5934" dependencies = [ - "amplify", + "amplify 4.7.0", "amplify_syn", "proc-macro2", "quote", @@ -351,7 +363,7 @@ version = "0.11.0-beta.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "538b69bbb2f7259c1d07334fa8adae0006c8b559efbdb6daafacb6df249b897b" dependencies = [ - "amplify", + "amplify 4.7.0", "commit_encoding_derive", "rand", "ripemd", @@ -573,6 +585,14 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2b8f3a258db515d5e91a904ce4ae3f73e091149b90cadbdb93d210bee07f63b" +[[package]] +name = "nonasync" +version = "0.1.0" +source = "git+https://github.com/rust-amplify/amplify-nonasync#9c6ab8f0e19d80cc787633bad328e7817c256de4" +dependencies = [ + "amplify 5.0.0-beta.1", +] + [[package]] name = "num-traits" version = "0.2.19" @@ -663,7 +683,7 @@ version = "0.11.0-beta.7" source = "git+https://github.com/RGB-WG/rgb-core?branch=nonce#d465448967220b5b5575557fab850a899ae104a4" dependencies = [ "aluvm", - "amplify", + "amplify 4.7.0", "baid64", "bp-core", "chrono", @@ -682,7 +702,7 @@ dependencies = [ name = "rgb-invoice" version = "0.11.0-beta.7" dependencies = [ - "amplify", + "amplify 4.7.0", "baid64", "bp-core", "bp-invoice", @@ -702,7 +722,7 @@ name = "rgb-std" version = "0.11.0-beta.7" dependencies = [ "aluvm", - "amplify", + "amplify 4.7.0", "ascii-armor", "baid64", "base85", @@ -711,6 +731,7 @@ dependencies = [ "commit_verify", "getrandom", "indexmap", + "nonasync", "rand", "rgb-core", "rgb-invoice", @@ -725,7 +746,7 @@ dependencies = [ name = "rgb-stl" version = "0.11.0-beta.7" dependencies = [ - "amplify", + "amplify 4.7.0", "commit_verify", "rgb-std", "strict_types", @@ -900,7 +921,7 @@ version = "2.7.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "662b8c3ff360ff33370e6875dd5bdcbf3cecc992241f30e5f7071227ef693451" dependencies = [ - "amplify", + "amplify 4.7.0", "half", "serde", "strict_encoding_derive", @@ -926,7 +947,7 @@ version = "2.7.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6e182f593e9c4f02ccfcea7929bef866cff12a3f8e213338ce48a706bb263c1" dependencies = [ - "amplify", + "amplify 4.7.0", "ascii-armor", "baid64", "half", @@ -1057,7 +1078,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f72ebd3b32f16ee8ace2bd3058c2bfa0f4820992bd4ea86e73ba228bb13dd2b0" dependencies = [ - "amplify", + "amplify 4.7.0", "strict_encoding", ] diff --git a/Cargo.toml b/Cargo.toml index a7c0065c..0e688fc4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ license = "Apache-2.0" [workspace.dependencies] amplify = "4.7.0" +nonasync = "0.1.0" ascii-armor = "0.7.1" baid64 = "0.2.2" strict_encoding = "2.7.0-rc.1" @@ -54,6 +55,7 @@ crate-type = ["cdylib", "rlib"] # We need this for WASM [dependencies] amplify = { workspace = true } +nonasync = { workspace = true } ascii-armor = { workspace = true } baid64 = { workspace = true } strict_encoding = { workspace = true } @@ -97,4 +99,5 @@ wasm-bindgen-test = "0.3" features = ["all"] [patch.crates-io] -rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "nonce" } +nonasync = { git = "https://github.com/rust-amplify/amplify-nonasync" } +rgb-core = { git = "https://github.com/RGB-WG/rgb-core", branch = "nonce" } \ No newline at end of file diff --git a/src/persistence/fs.rs b/src/persistence/fs.rs new file mode 100644 index 00000000..f7c26316 --- /dev/null +++ b/src/persistence/fs.rs @@ -0,0 +1,90 @@ +// RGB standard library for working with smart contracts on Bitcoin & Lightning +// +// SPDX-License-Identifier: Apache-2.0 +// +// Written in 2019-2024 by +// Dr Maxim Orlovsky +// +// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::path::PathBuf; + +use amplify::confinement::U32 as U32MAX; +use nonasync::persistence::{PersistenceError, PersistenceProvider}; +use strict_encoding::{StrictDeserialize, StrictSerialize}; + +use crate::persistence::{MemIndex, MemStash, MemState}; + +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct FsBinStore { + pub stash: PathBuf, + pub state: PathBuf, + pub index: PathBuf, +} + +impl FsBinStore { + pub fn new(path: PathBuf) -> Self { + let mut stash = path.clone(); + stash.push("stash.dat"); + let mut state = path.clone(); + state.push("state.dat"); + let mut index = path.clone(); + index.push("index.dat"); + + Self { + stash, + state, + index, + } + } +} +impl PersistenceProvider for FsBinStore { + fn load(&self) -> Result { + MemStash::strict_deserialize_from_file::(&self.stash) + .map_err(PersistenceError::with) + } + + fn store(&self, object: &MemStash) -> Result<(), PersistenceError> { + object + .strict_serialize_to_file::(&self.stash) + .map_err(PersistenceError::with) + } +} + +impl PersistenceProvider for FsBinStore { + fn load(&self) -> Result { + MemState::strict_deserialize_from_file::(&self.state) + .map_err(PersistenceError::with) + } + + fn store(&self, object: &MemState) -> Result<(), PersistenceError> { + object + .strict_serialize_to_file::(&self.state) + .map_err(PersistenceError::with) + } +} + +impl PersistenceProvider for FsBinStore { + fn load(&self) -> Result { + MemIndex::strict_deserialize_from_file::(&self.index) + .map_err(PersistenceError::with) + } + + fn store(&self, object: &MemIndex) -> Result<(), PersistenceError> { + object + .strict_serialize_to_file::(&self.index) + .map_err(PersistenceError::with) + } +} diff --git a/src/persistence/index.rs b/src/persistence/index.rs index 247e8cee..bc17a46d 100644 --- a/src/persistence/index.rs +++ b/src/persistence/index.rs @@ -24,6 +24,7 @@ use std::error::Error; use std::fmt::Debug; use amplify::confinement; +use nonasync::persistence::Persisting; use rgb::{ Assign, AssignmentType, BundleId, ContractId, ExposedState, Extension, Genesis, GenesisSeal, GraphSeal, OpId, Operation, Opout, TransitionBundle, TypedAssigns, XChain, XOutputSeal, @@ -31,7 +32,7 @@ use rgb::{ }; use crate::containers::{BundledWitness, ConsignmentExt, ToWitnessId}; -use crate::persistence::{StoreError, StoreTransaction}; +use crate::persistence::{MemError, StoreTransaction}; use crate::SecretSeal; #[derive(Debug, Display, Error, From)] @@ -84,7 +85,7 @@ impl From::Error>> f } } -impl From for IndexWriteError { +impl From for IndexWriteError { fn from(err: confinement::Error) -> Self { IndexWriteError::Connectivity(err.into()) } } @@ -349,7 +350,7 @@ impl StoreTransaction for Index

{ fn rollback_transaction(&mut self) { self.provider.rollback_transaction() } } -pub trait IndexProvider: Debug + IndexReadProvider + IndexWriteProvider {} +pub trait IndexProvider: Debug + Persisting + IndexReadProvider + IndexWriteProvider {} pub trait IndexReadProvider { type Error: Clone + Eq + Error; diff --git a/src/persistence/memory.rs b/src/persistence/memory.rs index 78b6a7ce..96eb56c6 100644 --- a/src/persistence/memory.rs +++ b/src/persistence/memory.rs @@ -35,6 +35,7 @@ use amplify::confinement::{ use amplify::num::u24; use bp::dbc::tapret::TapretCommitment; use commit_verify::{CommitId, Conceal}; +use nonasync::persistence::{Persistence, PersistenceError, Persisting}; use rgb::validation::ResolveWitness; use rgb::vm::{ ContractStateAccess, ContractStateEvolve, GlobalContractState, GlobalOrd, GlobalStateIter, @@ -54,8 +55,8 @@ use super::{ ContractIfaceError, ContractStateRead, ContractStateWrite, IndexInconsistency, IndexProvider, IndexReadError, IndexReadProvider, IndexWriteError, IndexWriteProvider, SchemaIfaces, StashInconsistency, StashProvider, StashProviderError, StashReadProvider, StashWriteProvider, - StateInconsistency, StateProvider, StateReadProvider, StateWriteProvider, StoreError, - StoreProvider, StoreTransaction, Stored, UpdateRes, + StateInconsistency, StateProvider, StateReadProvider, StateWriteProvider, StoreTransaction, + UpdateRes, }; use crate::containers::{ AnchorSet, ContentId, ContentRef, ContentSigs, SealWitness, SigBlob, Supplement, TrustLevel, @@ -64,6 +65,16 @@ use crate::contract::{GlobalOut, KnownState, OpWitness, OutputAssignment}; use crate::interface::{Iface, IfaceClass, IfaceId, IfaceImpl, IfaceRef}; use crate::LIB_NAME_RGB_STORAGE; +#[derive(Debug, Display, Error, From)] +#[display(inner)] +pub enum MemError { + #[from] + Persistence(PersistenceError), + + #[from] + Confinement(confinement::Error), +} + ////////// // STASH ////////// @@ -74,17 +85,9 @@ use crate::LIB_NAME_RGB_STORAGE; #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_STORAGE, dumb = Self::in_memory())] pub struct MemStash { - #[getter(prefix = "is_", as_copy)] - #[strict_type(skip)] - dirty: bool, - - #[getter(prefix = "is_", as_copy)] - #[strict_type(skip)] - autosave: bool, - #[getter(skip)] #[strict_type(skip)] - store_provider: Option>>, + persistence: Option>, schemata: TinyOrdMap, ifaces: TinyOrdMap, @@ -107,9 +110,7 @@ impl StrictDeserialize for MemStash {} impl MemStash { pub fn in_memory() -> Self { Self { - dirty: false, - autosave: false, - store_provider: None, + persistence: none!(), schemata: empty!(), ifaces: empty!(), geneses: empty!(), @@ -127,21 +128,23 @@ impl MemStash { } } -impl StoreTransaction for MemStash { - type TransactionErr = StoreError; +impl Persisting for MemStash { + #[inline] + fn persistence(&self) -> Option<&Persistence> { self.persistence.as_ref() } + #[inline] + fn persistence_mut(&mut self) -> Option<&mut Persistence> { self.persistence.as_mut() } +} +impl StoreTransaction for MemStash { + type TransactionErr = MemError; + #[inline] fn begin_transaction(&mut self) -> Result<(), Self::TransactionErr> { - self.dirty = true; + self.mark_dirty(); Ok(()) } - - fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr> { - if self.dirty && self.autosave { - self.store()?; - } - Ok(()) - } - + #[inline] + fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr> { Ok(self.store()?) } + #[inline] fn rollback_transaction(&mut self) { unreachable!() } } @@ -331,7 +334,7 @@ impl StashReadProvider for MemStash { } impl StashWriteProvider for MemStash { - type Error = StoreError; + type Error = MemError; fn replace_schema(&mut self, schema: Schema) -> Result { let schema_id = schema.schema_id(); @@ -463,17 +466,9 @@ impl StashWriteProvider for MemStash { #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_STORAGE, dumb = Self::in_memory())] pub struct MemState { - #[getter(prefix = "is_", as_copy)] - #[strict_type(skip)] - dirty: bool, - - #[getter(prefix = "is_", as_copy)] - #[strict_type(skip)] - autosave: bool, - #[getter(skip)] #[strict_type(skip)] - store_provider: Option>>, + persistence: Option>, witnesses: LargeOrdMap, contracts: TinyOrdMap, @@ -485,30 +480,30 @@ impl StrictDeserialize for MemState {} impl MemState { pub fn in_memory() -> Self { Self { - dirty: false, - autosave: false, - store_provider: None, + persistence: none!(), witnesses: empty!(), contracts: empty!(), } } } -impl StoreTransaction for MemState { - type TransactionErr = StoreError; +impl Persisting for MemState { + #[inline] + fn persistence(&self) -> Option<&Persistence> { self.persistence.as_ref() } + #[inline] + fn persistence_mut(&mut self) -> Option<&mut Persistence> { self.persistence.as_mut() } +} +impl StoreTransaction for MemState { + type TransactionErr = MemError; + #[inline] fn begin_transaction(&mut self) -> Result<(), Self::TransactionErr> { - self.dirty = true; - Ok(()) - } - - fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr> { - if self.dirty && self.autosave { - self.store()?; - } + self.mark_dirty(); Ok(()) } - + #[inline] + fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr> { Ok(self.store()?) } + #[inline] fn rollback_transaction(&mut self) { unreachable!() } } @@ -557,7 +552,7 @@ impl StateReadProvider for MemState { impl StateWriteProvider for MemState { type ContractWrite<'a> = MemContractWriter<'a>; - type Error = StoreError; + type Error = MemError; fn register_contract( &mut self, @@ -1036,9 +1031,10 @@ impl ContractStateEvolve for MemContract { } .map_err(|err| { // TODO: remove once evolve_state would accept arbitrary errors - *err.0 - .downcast::() - .expect("only confinement errors are possible") + match err { + MemError::Persistence(_) => unreachable!("only confinement errors are possible"), + MemError::Confinement(e) => e, + } })?; Ok(()) } @@ -1094,7 +1090,7 @@ pub struct MemContractWriter<'mem> { } impl<'mem> ContractStateWrite for MemContractWriter<'mem> { - type Error = StoreError; + type Error = MemError; /// # Panics /// @@ -1168,17 +1164,9 @@ pub struct ContractIndex { #[derive(StrictType, StrictDumb, StrictEncode, StrictDecode)] #[strict_type(lib = LIB_NAME_RGB_STORAGE, dumb = Self::in_memory())] pub struct MemIndex { - #[getter(prefix = "is_", as_copy)] - #[strict_type(skip)] - dirty: bool, - - #[getter(prefix = "is_", as_copy)] - #[strict_type(skip)] - autosave: bool, - #[getter(skip)] #[strict_type(skip)] - store_provider: Option>>, + persistence: Option>, op_bundle_index: MediumOrdMap, bundle_contract_index: MediumOrdMap, @@ -1193,9 +1181,7 @@ impl StrictDeserialize for MemIndex {} impl MemIndex { pub fn in_memory() -> Self { Self { - dirty: false, - autosave: false, - store_provider: None, + persistence: None, op_bundle_index: empty!(), bundle_contract_index: empty!(), bundle_witness_index: empty!(), @@ -1205,21 +1191,23 @@ impl MemIndex { } } -impl StoreTransaction for MemIndex { - type TransactionErr = StoreError; +impl Persisting for MemIndex { + #[inline] + fn persistence(&self) -> Option<&Persistence> { self.persistence.as_ref() } + #[inline] + fn persistence_mut(&mut self) -> Option<&mut Persistence> { self.persistence.as_mut() } +} +impl StoreTransaction for MemIndex { + type TransactionErr = MemError; + #[inline] fn begin_transaction(&mut self) -> Result<(), Self::TransactionErr> { - self.dirty = true; - Ok(()) - } - - fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr> { - if self.dirty && self.autosave { - self.store()?; - } + self.mark_dirty(); Ok(()) } - + #[inline] + fn commit_transaction(&mut self) -> Result<(), Self::TransactionErr> { Ok(self.store()?) } + #[inline] fn rollback_transaction(&mut self) { unreachable!() } } @@ -1314,7 +1302,7 @@ impl IndexReadProvider for MemIndex { } impl IndexWriteProvider for MemIndex { - type Error = StoreError; + type Error = MemError; fn register_contract(&mut self, contract_id: ContractId) -> Result { if !self.contract_index.contains_key(&contract_id) { @@ -1452,131 +1440,3 @@ impl IndexWriteProvider for MemIndex { Ok(()) } } - -mod store { - use crate::persistence::store::Stored; - use crate::persistence::{MemIndex, MemStash, MemState, StoreError, StoreProvider}; - - impl Stored for MemStash { - fn new_stored(provider: impl StoreProvider + 'static, autosave: bool) -> Self { - Self { - dirty: true, - autosave, - store_provider: Some(Box::new(provider)), - ..Self::in_memory() - } - } - - fn load( - provider: impl StoreProvider + 'static, - autosave: bool, - ) -> Result { - let mut me = provider.load()?; - me.autosave = autosave; - me.store_provider = Some(Box::new(provider)); - Ok(me) - } - - fn is_dirty(&self) -> bool { self.dirty } - - fn autosave(&mut self) { self.autosave = true; } - - fn make_stored(&mut self, provider: impl StoreProvider + 'static) -> bool { - let res = self.store_provider.is_some(); - self.store_provider = Some(Box::new(provider)); - self.dirty = true; - res - } - - fn store(&self) -> Result<(), StoreError> { - if self.is_dirty() { - if let Some(provider) = &self.store_provider { - provider.store(self)?; - } - } - Ok(()) - } - } - - impl Stored for MemState { - fn new_stored(provider: impl StoreProvider + 'static, autosave: bool) -> Self { - Self { - dirty: true, - autosave, - store_provider: Some(Box::new(provider)), - ..Self::in_memory() - } - } - - fn load( - provider: impl StoreProvider + 'static, - autosave: bool, - ) -> Result { - let mut me = provider.load()?; - me.autosave = autosave; - me.store_provider = Some(Box::new(provider)); - Ok(me) - } - - fn is_dirty(&self) -> bool { self.dirty } - - fn autosave(&mut self) { self.autosave = true; } - - fn make_stored(&mut self, provider: impl StoreProvider + 'static) -> bool { - let res = self.store_provider.is_some(); - self.store_provider = Some(Box::new(provider)); - self.dirty = true; - res - } - - fn store(&self) -> Result<(), StoreError> { - if self.is_dirty() { - if let Some(provider) = &self.store_provider { - provider.store(self)?; - } - } - Ok(()) - } - } - - impl Stored for MemIndex { - fn new_stored(provider: impl StoreProvider + 'static, autosave: bool) -> Self { - Self { - dirty: true, - autosave, - store_provider: Some(Box::new(provider)), - ..Self::in_memory() - } - } - - fn load( - provider: impl StoreProvider + 'static, - autosave: bool, - ) -> Result { - let mut me = provider.load()?; - me.autosave = autosave; - me.store_provider = Some(Box::new(provider)); - Ok(me) - } - - fn is_dirty(&self) -> bool { self.dirty } - - fn autosave(&mut self) { self.autosave = true; } - - fn make_stored(&mut self, provider: impl StoreProvider + 'static) -> bool { - let res = self.store_provider.is_some(); - self.store_provider = Some(Box::new(provider)); - self.dirty = true; - res - } - - fn store(&self) -> Result<(), StoreError> { - if self.is_dirty() { - if let Some(provider) = &self.store_provider { - provider.store(self)?; - } - } - Ok(()) - } - } -} diff --git a/src/persistence/mod.rs b/src/persistence/mod.rs index 591ce935..321f7b14 100644 --- a/src/persistence/mod.rs +++ b/src/persistence/mod.rs @@ -36,13 +36,16 @@ mod state; mod index; mod memory; -mod store; +#[cfg(feature = "fs")] +pub mod fs; pub use index::{ Index, IndexError, IndexInconsistency, IndexProvider, IndexReadError, IndexReadProvider, IndexWriteError, IndexWriteProvider, }; -pub use memory::{MemContract, MemContractState, MemGlobalState, MemIndex, MemStash, MemState}; +pub use memory::{ + MemContract, MemContractState, MemError, MemGlobalState, MemIndex, MemStash, MemState, +}; pub use stash::{ ProviderError as StashProviderError, SchemaIfaces, Stash, StashDataError, StashError, StashInconsistency, StashProvider, StashReadProvider, StashWriteProvider, @@ -55,7 +58,6 @@ pub use stock::{ ComposeError, ConsignError, ContractIfaceError, FasciaError, InputError as StockInputError, Stock, StockError, StockErrorAll, StockErrorMem, UpdateRes, }; -pub use store::{StockStoreProvider, StoreError, StoreProvider, Stored}; pub trait StoreTransaction { type TransactionErr: std::error::Error; diff --git a/src/persistence/stash.rs b/src/persistence/stash.rs index d5f322b4..535594d0 100644 --- a/src/persistence/stash.rs +++ b/src/persistence/stash.rs @@ -29,6 +29,7 @@ use amplify::confinement::{Confined, MediumBlob, TinyOrdMap}; use bp::dbc::anchor::MergeError; use bp::dbc::tapret::TapretCommitment; use commit_verify::mpc; +use nonasync::persistence::Persisting; use rgb::validation::Scripts; use rgb::{ AttachId, BundleId, ContractId, Extension, Genesis, GraphSeal, Identity, OpId, Operation, @@ -618,7 +619,7 @@ impl StoreTransaction for Stash

{ fn rollback_transaction(&mut self) { self.provider.rollback_transaction() } } -pub trait StashProvider: Debug + StashReadProvider + StashWriteProvider {} +pub trait StashProvider: Debug + Persisting + StashReadProvider + StashWriteProvider {} pub trait StashReadProvider { /// Error type which must indicate problems on data retrieval. diff --git a/src/persistence/state.rs b/src/persistence/state.rs index 2ddbab6b..94a93fd2 100644 --- a/src/persistence/state.rs +++ b/src/persistence/state.rs @@ -26,6 +26,7 @@ use std::fmt::Debug; use std::iter; use invoice::Amount; +use nonasync::persistence::Persisting; use rgb::validation::{ResolveWitness, WitnessResolverError}; use rgb::vm::{ContractStateAccess, WitnessOrd}; use rgb::{ @@ -254,7 +255,7 @@ impl StoreTransaction for State

{ fn rollback_transaction(&mut self) { self.provider.rollback_transaction() } } -pub trait StateProvider: Debug + StateReadProvider + StateWriteProvider {} +pub trait StateProvider: Debug + Persisting + StateReadProvider + StateWriteProvider {} pub trait StateReadProvider { type ContractRead<'a>: ContractStateRead diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index 8356ab56..0951994b 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -32,6 +32,7 @@ use bp::seals::txout::CloseMethod; use bp::Vout; use chrono::Utc; use invoice::{Amount, Beneficiary, InvoiceState, NonFungible, RgbInvoice}; +use nonasync::persistence::{PersistenceError, PersistenceProvider}; use rgb::validation::{DbcProof, EAnchor, ResolveWitness, WitnessResolverError}; use rgb::{ validation, AssignmentType, BlindingFactor, BundleId, ContractId, DataState, GraphSeal, @@ -45,7 +46,7 @@ use super::{ IndexWriteProvider, MemIndex, MemStash, MemState, PersistedState, SchemaIfaces, Stash, StashDataError, StashError, StashInconsistency, StashProvider, StashReadProvider, StashWriteProvider, State, StateError, StateInconsistency, StateProvider, StateReadProvider, - StateWriteProvider, StockStoreProvider, StoreError, StoreProvider, StoreTransaction, Stored, + StateWriteProvider, StoreTransaction, }; use crate::containers::{ AnchorSet, AnchoredBundles, Batch, BuilderSeal, BundledWitness, Consignment, ContainerVer, @@ -375,44 +376,48 @@ impl Stock { } } -impl Stock -where - S: Stored, - H: Stored, - I: Stored, -{ - pub fn load

(provider: P, autosave: bool) -> Result - where P: StoreProvider + 'static { - let mut stock = provider.load()?; - if autosave { - stock.stash.as_provider_mut().autosave(); - stock.state.as_provider_mut().autosave(); - stock.index.as_provider_mut().autosave(); - } - Ok(stock) - } - - pub fn autosave(&mut self) { - self.stash.as_provider_mut().autosave(); - self.state.as_provider_mut().autosave(); - self.index.as_provider_mut().autosave(); +impl Stock { + pub fn load

(provider: P, autosave: bool) -> Result + where P: Clone + + PersistenceProvider + + PersistenceProvider + + PersistenceProvider + + 'static { + let stash = S::load(provider.clone(), autosave)?; + let state = H::load(provider.clone(), autosave)?; + let index = I::load(provider, autosave)?; + Ok(Self::with(stash, state, index)) } - pub fn is_dirty(&self) -> bool { - self.as_stash_provider().is_dirty() || - self.as_state_provider().is_dirty() || - self.as_index_provider().is_dirty() + pub fn make_persistent

( + &mut self, + provider: P, + autosave: bool, + ) -> Result + where + P: Clone + + PersistenceProvider + + PersistenceProvider + + PersistenceProvider + + 'static, + { + Ok(self + .as_stash_provider_mut() + .make_persistent(provider.clone(), autosave)? + && self + .as_state_provider_mut() + .make_persistent(provider.clone(), autosave)? + && self + .as_index_provider_mut() + .make_persistent(provider, autosave)?) } - pub fn make_stored

(&mut self, provider: P) -> bool - where P: StockStoreProvider + 'static { - provider.make_stored(self) - } + pub fn store(&mut self) -> Result<(), PersistenceError> { + // TODO: Revert on failure - pub fn store(&self) -> Result<(), StoreError> { - self.as_stash_provider().store()?; - self.as_state_provider().store()?; - self.as_index_provider().store()?; + self.as_stash_provider_mut().store()?; + self.as_state_provider_mut().store()?; + self.as_index_provider_mut().store()?; Ok(()) } diff --git a/src/persistence/store.rs b/src/persistence/store.rs deleted file mode 100644 index ebe5e62c..00000000 --- a/src/persistence/store.rs +++ /dev/null @@ -1,169 +0,0 @@ -// RGB standard library for working with smart contracts on Bitcoin & Lightning -// -// SPDX-License-Identifier: Apache-2.0 -// -// Written in 2019-2024 by -// Dr Maxim Orlovsky -// -// Copyright (C) 2019-2024 LNP/BP Standards Association. All rights reserved. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -use std::error::Error; -use std::fmt::Debug; - -use amplify::confinement; -use strict_encoding::{DeserializeError, SerializeError}; - -use crate::persistence::{IndexProvider, StashProvider, StateProvider, Stock}; - -#[derive(Debug, Display, Error)] -#[display(inner)] -pub struct StoreError(pub Box); - -impl From for StoreError { - fn from(err: confinement::Error) -> Self { Self(Box::new(err)) } -} - -impl From for StoreError { - fn from(err: SerializeError) -> Self { Self(Box::new(err)) } -} - -impl From for StoreError { - fn from(err: DeserializeError) -> Self { Self(Box::new(err)) } -} - -pub trait StockStoreProvider: - StoreProvider> -{ - fn make_stored(&self, stock: &mut Stock) -> bool; -} - -pub trait StoreProvider: Send + Debug { - fn load(&self) -> Result; - fn store(&self, object: &T) -> Result<(), StoreError>; -} - -pub trait Stored: Sized { - fn new_stored(provider: impl StoreProvider + 'static, autosave: bool) -> Self; - fn load( - provider: impl StoreProvider + 'static, - autosave: bool, - ) -> Result; - - fn is_dirty(&self) -> bool; - fn autosave(&mut self); - fn make_stored(&mut self, provider: impl StoreProvider + 'static) -> bool; - - fn store(&self) -> Result<(), StoreError>; -} - -#[cfg(feature = "fs")] -mod fs { - use std::path::PathBuf; - - use amplify::confinement::U32 as U32MAX; - use strict_encoding::{StrictDeserialize, StrictSerialize}; - - use super::*; - use crate::persistence::{MemIndex, MemStash, MemState, Stock, Stored}; - - impl StoreProvider for PathBuf { - fn load(&self) -> Result { - Ok(MemStash::strict_deserialize_from_file::(&self)?) - } - - fn store(&self, object: &MemStash) -> Result<(), StoreError> { - object.strict_serialize_to_file::(&self)?; - Ok(()) - } - } - - impl StoreProvider for PathBuf { - fn load(&self) -> Result { - Ok(MemState::strict_deserialize_from_file::(&self)?) - } - - fn store(&self, object: &MemState) -> Result<(), StoreError> { - object.strict_serialize_to_file::(&self)?; - Ok(()) - } - } - - impl StoreProvider for PathBuf { - fn load(&self) -> Result { - Ok(MemIndex::strict_deserialize_from_file::(&self)?) - } - - fn store(&self, object: &MemIndex) -> Result<(), StoreError> { - object.strict_serialize_to_file::(&self)?; - Ok(()) - } - } - - impl StoreProvider for PathBuf { - fn load(&self) -> Result { - let mut filename = self.to_owned(); - filename.push("stash.dat"); - let stash: MemStash = filename.load()?; - - let mut filename = self.to_owned(); - filename.push("state.dat"); - let state: MemState = filename.load()?; - - let mut filename = self.to_owned(); - filename.push("index.dat"); - let index: MemIndex = filename.load()?; - - Ok(Stock::with(stash, state, index)) - } - - fn store(&self, stock: &Stock) -> Result<(), StoreError> { - // TODO: Revert files on failure - - let mut filename = self.to_owned(); - filename.push("stash.dat"); - filename.store(stock.as_stash_provider())?; - - let mut filename = self.to_owned(); - filename.push("state.dat"); - filename.store(stock.as_state_provider())?; - - let mut filename = self.to_owned(); - filename.push("index.dat"); - filename.store(stock.as_index_provider())?; - - Ok(()) - } - } - - impl StockStoreProvider for PathBuf { - fn make_stored(&self, stock: &mut Stock) -> bool { - let mut filename = self.to_owned(); - filename.push("stash.dat"); - let _1 = stock.as_stash_provider_mut().make_stored(filename); - - let mut filename = self.to_owned(); - filename.push("state.dat"); - let _2 = stock.as_state_provider_mut().make_stored(filename); - - let mut filename = self.to_owned(); - filename.push("index.dat"); - let _3 = stock.as_index_provider_mut().make_stored(filename); - - assert_eq!(_1, _2); - assert_eq!(_2, _3); - _1 - } - } -}