diff --git a/Cargo.lock b/Cargo.lock index 6168ec28df6..0b9beaefefb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -683,6 +683,16 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + [[package]] name = "constant_time_eq" version = "0.2.5" @@ -1092,6 +1102,7 @@ name = "drive" version = "0.24.0-dev.1" dependencies = [ "base64 0.21.0", + "bincode 2.0.0-rc.3", "bs58", "byteorder", "chrono", @@ -3116,6 +3127,16 @@ dependencies = [ "serde", ] +[[package]] +name = "serde-wasm-bindgen" +version = "0.5.0" +source = "git+https://github.com/QuantumExplorer/serde-wasm-bindgen?branch=feat/not_human_readable#121d1f7fbf62cb97f74b91626a1b23851098cc82" +dependencies = [ + "js-sys", + "serde", + "wasm-bindgen", +] + [[package]] name = "serde_bytes" version = "0.11.9" @@ -3912,6 +3933,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.84" @@ -3941,6 +3974,25 @@ version = "0.2.84" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +[[package]] +name = "wasm-dpp" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-trait", + "console_error_panic_hook", + "dpp", + "itertools", + "js-sys", + "serde", + "serde-wasm-bindgen", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "web-sys" version = "0.3.61" diff --git a/packages/rs-drive-abci/src/execution/engine.rs b/packages/rs-drive-abci/src/execution/engine.rs index e65032f28fa..12a3339db78 100644 --- a/packages/rs-drive-abci/src/execution/engine.rs +++ b/packages/rs-drive-abci/src/execution/engine.rs @@ -1,6 +1,7 @@ use bls_signatures; use dashcore::hashes::Hash; use dashcore::{QuorumHash, Txid}; +use dpp::bincode; use dpp::consensus::basic::identity::IdentityInsufficientBalanceError; use dpp::consensus::ConsensusError; use dpp::state_transition::StateTransition; @@ -21,6 +22,7 @@ use crate::abci::withdrawal::WithdrawalTxs; use crate::abci::AbciError; use crate::block::{BlockExecutionContext, BlockStateInfo}; use crate::error::execution::ExecutionError; +use crate::error::serialization::SerializationError; use crate::error::Error; use crate::execution::block_proposal::BlockProposal; use crate::execution::execution_event::ExecutionResult::{ @@ -238,6 +240,7 @@ where let last_block_core_height = state.known_core_height_or(self.config.abci.genesis_core_height); let hpmn_list_len = state.hpmn_list_len(); + let quorum_hash = state.current_validator_set_quorum_hash; drop(state); // Init block execution context @@ -345,6 +348,9 @@ where transaction, )?; + // Store ephemeral data + self.store_ephemeral_data(&block_info, &quorum_hash, transaction)?; + let root_hash = self .drive .grove @@ -365,6 +371,52 @@ where })) } + // TODO: remove function from here + fn store_ephemeral_data( + &self, + block_info: &BlockInfo, + quorum_hash: &QuorumHash, + transaction: &Transaction, + ) -> Result<(), Error> { + // we need to serialize the block info + let mut serialized_block_info = vec![]; + bincode::encode_into_slice( + block_info, + serialized_block_info.as_mut_slice(), + bincode::config::standard(), + ) + .map_err(|_| { + Error::Serialization(SerializationError::CorruptedSerialization( + "failed to serialize block info".to_string(), + )) + })?; + + // next we need to store this data in groveb + self.drive + .grove + .put_aux( + b"saved_state", + &serialized_block_info, + None, + Some(transaction), + ) + .unwrap() + .map_err(|e| Error::Drive(GroveDB(e)))?; + + self.drive + .grove + .put_aux( + b"saved_quorum_hash", + &quorum_hash.into_inner(), + None, + Some(&transaction), + ) + .unwrap() + .map_err(|e| Error::Drive(GroveDB(e)))?; + + Ok(()) + } + /// Update the current quorums if the core_height changes pub fn update_state_cache_and_quorums( &self, diff --git a/packages/rs-drive-abci/src/execution/masternode_identities/mod.rs b/packages/rs-drive-abci/src/execution/masternode_identities/mod.rs index 53df0fcd088..4f3ea33057b 100644 --- a/packages/rs-drive-abci/src/execution/masternode_identities/mod.rs +++ b/packages/rs-drive-abci/src/execution/masternode_identities/mod.rs @@ -599,6 +599,7 @@ where } } +/* #[cfg(test)] mod tests { use crate::config::PlatformConfig; @@ -733,3 +734,4 @@ mod tests { #[test] fn test_update_owner_identity() {} } +*/ diff --git a/packages/rs-drive-abci/src/platform/mod.rs b/packages/rs-drive-abci/src/platform/mod.rs index 9889fcc2b0c..505af2d55c4 100644 --- a/packages/rs-drive-abci/src/platform/mod.rs +++ b/packages/rs-drive-abci/src/platform/mod.rs @@ -34,7 +34,7 @@ use crate::block::BlockExecutionContext; use crate::config::PlatformConfig; use crate::error::execution::ExecutionError; use crate::error::Error; -use crate::rpc::core::DefaultCoreRPC; +use crate::rpc::core::{CoreRPCLike, DefaultCoreRPC}; use crate::state::PlatformState; use drive::drive::Drive; @@ -42,9 +42,16 @@ use drive::drive::defaults::PROTOCOL_VERSION; use std::path::Path; use std::sync::RwLock; +use crate::error::serialization::SerializationError; +use crate::error::Error::Serialization; use crate::rpc::core::MockCoreRPCLike; -use dpp::dashcore::hashes::hex::FromHex; -use dpp::dashcore::BlockHash; +use dashcore::hashes::hex::FromHex; +use dashcore::hashes::Hash; +use dashcore::{BlockHash, QuorumHash}; +use dpp::bincode; +use drive::drive::block_info::BlockInfo; +use drive::error::drive::DriveError; +use drive::error::Error::GroveDB; use serde_json::json; mod state_repository; @@ -159,7 +166,10 @@ impl Platform { path: P, config: Option, core_rpc: C, - ) -> Result, Error> { + ) -> Result, Error> + where + C: CoreRPCLike, + { let config = config.unwrap_or_default(); let drive = Drive::open(path, config.drive.clone()).map_err(Error::Drive)?; @@ -172,6 +182,121 @@ impl Platform { .map_err(Error::Drive)? .unwrap_or(PROTOCOL_VERSION); + // TODO: factor out key so we don't duplicate + let maybe_serialized_block_info = drive + .grove + .get_aux(b"saved_state", None) + .unwrap() + .map_err(|e| Error::Drive(GroveDB(e)))?; + + if let Some(serialized_block_info) = maybe_serialized_block_info { + Platform::open_with_client_saved_state::

( + drive, + core_rpc, + config, + serialized_block_info, + current_protocol_version_in_consensus, + next_epoch_protocol_version, + ) + } else { + Platform::open_with_client_no_saved_state::

( + drive, + core_rpc, + config, + current_protocol_version_in_consensus, + next_epoch_protocol_version, + ) + } + } + + /// Open Platform with Drive and block execution context from saved state. + pub fn open_with_client_saved_state>( + drive: Drive, + core_rpc: C, + config: PlatformConfig, + serialized_block_info: Vec, + current_protocol_version_in_consensus: u32, + next_epoch_protocol_version: u32, + ) -> Result, Error> + where + C: CoreRPCLike, + { + let block_info: BlockInfo = + bincode::decode_from_slice(&serialized_block_info, bincode::config::standard()) + .map_err(|e| { + Serialization(SerializationError::CorruptedDeserialization( + "failed to deserialize saved state".to_string(), + )) + })? + .0; + + let maybe_quorum_hash = drive + .grove + .get_aux(b"saved_quorum_hash", None) + .unwrap() + .map_err(|e| Error::Drive(GroveDB(e)))?; + + // TODO: remove unwrap + let current_validator_set_quorum_hash = + QuorumHash::from_slice(&maybe_quorum_hash.unwrap()).unwrap(); + + let state = PlatformState { + last_committed_block_info: Some(block_info), + current_protocol_version_in_consensus, + next_epoch_protocol_version, + quorums_extended_info: Default::default(), + current_validator_set_quorum_hash, + validator_sets: Default::default(), + full_masternode_list: Default::default(), + hpmn_masternode_list: Default::default(), + }; + + let core_height = state.core_height(); + let block_info = state + .last_committed_block_info + .clone() + .unwrap_or(BlockInfo::genesis()); + + let platform: Platform = Platform { + drive, + state: RwLock::new(state), + config, + block_execution_context: RwLock::new(None), + core_rpc, + }; + + let transaction = platform.drive.grove.start_transaction(); + let mut state_cache = platform.state.write().unwrap(); + platform.update_quorum_info(&mut state_cache, core_height)?; + platform.update_masternode_list( + &mut state_cache, + core_height, + &block_info, + &transaction, + )?; + drop(state_cache); + + platform + .drive + .grove + .commit_transaction(transaction) + .unwrap() + .map_err(|e| Error::Drive(GroveDB(e)))?; + + return Ok(platform); + } + + /// Open Platform with Drive and block execution context without saved state. + pub fn open_with_client_no_saved_state>( + drive: Drive, + core_rpc: C, + config: PlatformConfig, + current_protocol_version_in_consensus: u32, + next_epoch_protocol_version: u32, + ) -> Result, Error> + where + C: CoreRPCLike, + { let state = PlatformState { last_committed_block_info: None, current_protocol_version_in_consensus, diff --git a/packages/rs-drive-abci/src/state/genesis.rs b/packages/rs-drive-abci/src/state/genesis.rs index 249d82ef310..14793a75d5b 100644 --- a/packages/rs-drive-abci/src/state/genesis.rs +++ b/packages/rs-drive-abci/src/state/genesis.rs @@ -266,7 +266,8 @@ mod tests { assert_eq!( root_hash, [ - 223, 137, 33, 5, 253, 177, 248, 37, 0, 40, 198, 213, 196, 196, 66, 200, 71, 85, 103, 138, 52, 63, 102, 105, 27, 86, 102, 242, 79, 247, 217, 108 + 223, 137, 33, 5, 253, 177, 248, 37, 0, 40, 198, 213, 196, 196, 66, 200, 71, 85, + 103, 138, 52, 63, 102, 105, 27, 86, 102, 242, 79, 247, 217, 108 ] ) } diff --git a/packages/rs-drive/Cargo.toml b/packages/rs-drive/Cargo.toml index f50e49a9a19..90dedaad1ca 100644 --- a/packages/rs-drive/Cargo.toml +++ b/packages/rs-drive/Cargo.toml @@ -19,6 +19,7 @@ thiserror = { version = "1.0.30" } moka = { version = "0.10.1", features = ["future", "futures-util"]} nohash-hasher = { version = "0.2.0" } dpp = { path = "../rs-dpp", features = ["fixtures-and-mocks"] } +bincode = { version="2.0.0-rc.3", features=["serde"] } # optional dependencies bs58 = { version = "0.4.0", optional = true } diff --git a/packages/rs-drive/src/drive/block_info.rs b/packages/rs-drive/src/drive/block_info.rs index 42bb6fa3eb5..35c3026fc12 100644 --- a/packages/rs-drive/src/drive/block_info.rs +++ b/packages/rs-drive/src/drive/block_info.rs @@ -1,7 +1,9 @@ +use dpp::dashcore::QuorumHash; use crate::fee_pools::epochs::Epoch; +use dpp::bincode::{Encode, Decode}; /// Block information -#[derive(Clone, Default)] +#[derive(Clone, Default, Encode, Decode)] pub struct BlockInfo { /// Block time in milliseconds pub time_ms: u64, @@ -14,6 +16,9 @@ pub struct BlockInfo { /// Current fee epoch pub epoch: Epoch, + + // /// current quorum + // pub current_validator_set_quorum_hash: QuorumHash, } impl BlockInfo { diff --git a/packages/rs-drive/src/fee_pools/epochs/mod.rs b/packages/rs-drive/src/fee_pools/epochs/mod.rs index 42a251a7680..34da6525b7a 100644 --- a/packages/rs-drive/src/fee_pools/epochs/mod.rs +++ b/packages/rs-drive/src/fee_pools/epochs/mod.rs @@ -37,12 +37,13 @@ pub mod paths; use crate::fee::epoch::EpochIndex; use serde::{Deserialize, Serialize}; +use bincode::{Encode, Decode}; // TODO: I would call it EpochTree because it represent pool, // not just Epoch which is more abstract thing that we will probably need in future too /// Epoch struct -#[derive(Serialize, Deserialize, Default, Clone, Eq, PartialEq, Copy)] +#[derive(Serialize, Deserialize, Default, Clone, Eq, PartialEq, Copy, Encode, Decode)] #[serde(rename_all = "camelCase")] pub struct Epoch { /// Epoch index