diff --git a/.github/actions/sccache/action.yaml b/.github/actions/sccache/action.yaml index 14954b1f202..700c47e2f96 100644 --- a/.github/actions/sccache/action.yaml +++ b/.github/actions/sccache/action.yaml @@ -34,7 +34,7 @@ inputs: default: "true" version: description: "sccache version" - default: "0.8.2" + default: "0.9.1" required: false outputs: env_vars: diff --git a/Cargo.lock b/Cargo.lock index b0954299585..2439dc000d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -473,7 +473,7 @@ dependencies = [ "bitflags 2.9.0", "cexpr", "clang-sys", - "itertools 0.12.1", + "itertools 0.10.5", "lazy_static", "lazycell", "proc-macro2", @@ -2752,15 +2752,6 @@ dependencies = [ "either", ] -[[package]] -name = "itertools" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" -dependencies = [ - "either", -] - [[package]] name = "itertools" version = "0.13.0" @@ -4968,6 +4959,7 @@ dependencies = [ "hex", "lhash", "semver", + "serde_json", "tenderdash-proto", "thiserror 2.0.12", "tokio", @@ -5667,9 +5659,9 @@ dependencies = [ [[package]] name = "ureq-proto" -version = "0.3.0" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c51fe73e1d8c4e06bb2698286f7e7453c6fc90528d6d2e7fc36bb4e87fe09b1" +checksum = "b8e8862e186de3ad6ea1505dd071d179ec27aa7d2cb0798196c83f94625c8e9a" dependencies = [ "base64 0.22.1", "http", diff --git a/Dockerfile b/Dockerfile index c0411248e73..361e099e999 100644 --- a/Dockerfile +++ b/Dockerfile @@ -175,7 +175,7 @@ ENV NODE_ENV=${NODE_ENV} FROM deps-base AS deps-sccache # SCCACHE_VERSION must be the same as in github actions, to avoid cache incompatibility -ARG SCCHACHE_VERSION=0.8.2 +ARG SCCHACHE_VERSION=0.9.1 # Install sccache for caching RUN if [[ "$TARGETARCH" == "arm64" ]] ; then export SCC_ARCH=aarch64; else export SCC_ARCH=x86_64; fi; \ @@ -600,19 +600,24 @@ LABEL description="Drive ABCI Rust" RUN apk add --no-cache libgcc libstdc++ ENV DB_PATH=/var/lib/dash/rs-drive-abci/db +ENV CHECKPOINTS_PATH=/var/lib/dash/rs-drive-abci/db-checkpoints ENV REJECTIONS_PATH=/var/log/dash/rejected - -RUN mkdir -p /var/log/dash \ - /var/lib/dash/rs-drive-abci/db \ - ${REJECTIONS_PATH} +ENV SNAPSHOTS_ENABLED=true COPY --from=build-drive-abci /artifacts/drive-abci /usr/bin/drive-abci COPY packages/rs-drive-abci/.env.mainnet /var/lib/dash/rs-drive-abci/.env # Create a volume VOLUME /var/lib/dash/rs-drive-abci/db +VOLUME /var/lib/dash/rs-drive-abci/db-checkpoints VOLUME /var/log/dash +# Ensure required paths do exist +RUN mkdir -p /var/log/dash \ + ${DB_PATH} \ + ${CHECKPOINTS_PATH} \ + ${REJECTIONS_PATH} + # Double-check that we don't have missing deps RUN ldd /usr/bin/drive-abci @@ -622,6 +627,7 @@ RUN ldd /usr/bin/drive-abci ARG USERNAME=dash ARG USER_UID=1000 ARG USER_GID=$USER_UID + RUN addgroup -g $USER_GID $USERNAME && \ adduser -D -u $USER_UID -G $USERNAME -h /var/lib/dash/rs-drive-abci $USERNAME && \ chown -R $USER_UID:$USER_GID /var/lib/dash/rs-drive-abci /var/log/dash diff --git a/packages/dapi-grpc/Cargo.toml b/packages/dapi-grpc/Cargo.toml index 3ebadaca8ad..0c77317cd75 100644 --- a/packages/dapi-grpc/Cargo.toml +++ b/packages/dapi-grpc/Cargo.toml @@ -39,8 +39,6 @@ serde = ["dep:serde", "dep:serde_bytes", "tenderdash-proto/serde"] mocks = ["serde", "dep:serde_json"] [dependencies] -tenderdash-proto = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.4.0", tag = "v1.4.0", default-features = false } - prost = { version = "0.13" } futures-core = "0.3.30" tonic = { version = "0.13.0", features = [ @@ -51,6 +49,7 @@ tonic = { version = "0.13.0", features = [ serde = { version = "1.0.219", optional = true, features = ["derive"] } serde_bytes = { version = "0.11.12", optional = true } serde_json = { version = "1.0", optional = true } +tenderdash-proto = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.4.0", tag = "v1.4.0", default-features = false } dapi-grpc-macros = { path = "../rs-dapi-grpc-macros" } platform-version = { path = "../rs-platform-version" } diff --git a/packages/dashmate/configs/defaults/getBaseConfigFactory.js b/packages/dashmate/configs/defaults/getBaseConfigFactory.js index 1614216ad2a..4248ead0eec 100644 --- a/packages/dashmate/configs/defaults/getBaseConfigFactory.js +++ b/packages/dashmate/configs/defaults/getBaseConfigFactory.js @@ -305,11 +305,18 @@ export default function getBaseConfigFactory() { txProcessingTimeLimit: null, }, epochTime: 788400, + stateSync: { + snapshots: { + enabled: true, + frequency: 5, + maxLimit: 100, + }, + }, }, tenderdash: { mode: 'full', docker: { - image: 'dashpay/tenderdash:1', + image: 'dashpay/tenderdash:feat-statesync-improvements', }, p2p: { host: '0.0.0.0', @@ -412,6 +419,14 @@ export default function getBaseConfigFactory() { }, }, moniker: null, + stateSync: { + enabled: true, + retries: 3, + chunkRequestTimeout: '15s', + fetchersCount: 4, + maxConcurrentListSnapshots: 100, + maxConcurrentSnapshotChunk: 100, + }, }, }, sourcePath: null, diff --git a/packages/dashmate/configs/defaults/getLocalConfigFactory.js b/packages/dashmate/configs/defaults/getLocalConfigFactory.js index 42254deb5de..f6a5bd749e1 100644 --- a/packages/dashmate/configs/defaults/getLocalConfigFactory.js +++ b/packages/dashmate/configs/defaults/getLocalConfigFactory.js @@ -63,6 +63,9 @@ export default function getLocalConfigFactory(getBaseConfig) { metrics: { port: 46660, }, + stateSync: { + enabled: false, + }, }, abci: { epochTime: 1200, diff --git a/packages/dashmate/configs/getConfigFileMigrationsFactory.js b/packages/dashmate/configs/getConfigFileMigrationsFactory.js index a4cc5bfbb23..e9e06150269 100644 --- a/packages/dashmate/configs/getConfigFileMigrationsFactory.js +++ b/packages/dashmate/configs/getConfigFileMigrationsFactory.js @@ -1096,8 +1096,33 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) }); return configFile; }, + '2.1.0-dev.1': (configFile) => { + Object.entries(configFile.configs) + .forEach(([, options]) => { + options.platform.drive.tenderdash.stateSync = { + enabled: true, + retries: 3, + chunkRequestTimeout: '15s', + fetchersCount: 4, + maxConcurrentListSnapshots: 100, + maxConcurrentSnapshotChunk: 100, + }; + + options.platform.drive.abci.stateSync = { + snapshots: { + enabled: true, + frequency: 5, + maxLimit: 100, + }, + }; + }); + + configFile.configs.local.platform.drive.abci.stateSync.snapshots.enabled = false; + configFile.configs.local.platform.drive.tenderdash.stateSync.enabled = false; + + return configFile; + }, }; } - return getConfigFileMigrations; } diff --git a/packages/dashmate/docker-compose.yml b/packages/dashmate/docker-compose.yml index fb4cb02b0f3..08f1d34894c 100644 --- a/packages/dashmate/docker-compose.yml +++ b/packages/dashmate/docker-compose.yml @@ -58,6 +58,7 @@ services: logging: *default-logging volumes: - drive_abci_data:/var/lib/dash/rs-drive-abci/db + - drive_abci_checkpoints:/var/lib/dash/rs-drive-abci/db-checkpoints environment: - CHAIN_ID=${PLATFORM_DRIVE_TENDERDASH_GENESIS_CHAIN_ID:-devnet} - CORE_CONSENSUS_JSON_RPC_USERNAME=drive_consensus @@ -82,6 +83,7 @@ services: - INSTANT_LOCK_QUORUM_ACTIVE_SIGNERS=${PLATFORM_DRIVE_ABCI_INSTANT_LOCK_QUORUM_ACTIVE_SIGNERS:?err} - INSTANT_LOCK_QUORUM_ROTATION=${PLATFORM_DRIVE_ABCI_INSTANT_LOCK_QUORUM_ROTATION:?err} - DB_PATH=/var/lib/dash/rs-drive-abci/db + - GROVEDB_LATEST_FILE=/var/lib/dash/rs-drive-abci/db/latest_state - ABCI_CONSENSUS_BIND_ADDRESS=tcp://0.0.0.0:26658 - GRPC_BIND_ADDRESS=0.0.0.0:26670 - PROMETHEUS_BIND_ADDRESS=${PLATFORM_DRIVE_ABCI_METRICS_URL} @@ -92,6 +94,10 @@ services: - GROVEDB_VISUALIZER_ADDRESS=0.0.0.0:${PLATFORM_DRIVE_ABCI_GROVEDB_VISUALIZER_PORT:?err} - PROPOSER_TX_PROCESSING_TIME_LIMIT=${PLATFORM_DRIVE_ABCI_PROPOSER_TX_PROCESSING_TIME_LIMIT} - NETWORK=${NETWORK:?err} + - CHECKPOINTS_PATH=/var/lib/dash/rs-drive-abci/db-checkpoints + - SNAPSHOTS_ENABLED=${PLATFORM_DRIVE_ABCI_STATE_SYNC_SNAPSHOTS_ENABLED:?err} + - SNAPSHOTS_FREQUENCY=${PLATFORM_DRIVE_ABCI_STATE_SYNC_SNAPSHOTS_FREQUENCY:?err} + - MAX_NUM_SNAPSHOTS=${PLATFORM_DRIVE_ABCI_STATE_SYNC_SNAPSHOTS_MAX_LIMIT:?err} stop_grace_period: 30s expose: - 26658 @@ -226,6 +232,7 @@ services: volumes: core_data: drive_abci_data: + drive_abci_checkpoints: drive_tenderdash: networks: diff --git a/packages/dashmate/src/config/configJsonSchema.js b/packages/dashmate/src/config/configJsonSchema.js index 0f57fbbf50d..86bd798e1c4 100644 --- a/packages/dashmate/src/config/configJsonSchema.js +++ b/packages/dashmate/src/config/configJsonSchema.js @@ -949,6 +949,31 @@ export default { required: ['txProcessingTimeLimit'], additionalProperties: false, }, + stateSync: { + type: 'object', + properties: { + snapshots: { + type: 'object', + properties: { + enabled: { + type: 'boolean', + }, + frequency: { + type: 'integer', + minimum: 1, + }, + maxLimit: { + type: 'integer', + minimum: 1, + }, + }, + required: ['enabled', 'frequency', 'maxLimit'], + additionalProperties: false, + }, + }, + required: ['snapshots'], + additionalProperties: false, + }, }, additionalProperties: false, required: ['docker', 'logs', 'tokioConsole', 'validatorSet', 'chainLock', 'epochTime', 'metrics', 'grovedbVisualizer', 'proposer'], @@ -1208,8 +1233,37 @@ export default { genesis: { type: 'object', }, + stateSync: { + type: 'object', + properties: { + enabled: { + type: 'boolean', + }, + retries: { + type: 'integer', + minimum: 1, + }, + chunkRequestTimeout: { + $ref: '#/definitions/duration', + }, + fetchersCount: { + type: 'integer', + minimum: 1, + }, + maxConcurrentListSnapshots: { + type: 'integer', + minimum: 1, + }, + maxConcurrentSnapshotChunk: { + type: 'integer', + minimum: 1, + }, + }, + required: ['enabled', 'retries', 'chunkRequestTimeout', 'fetchersCount', 'maxConcurrentListSnapshots', 'maxConcurrentSnapshotChunk'], + additionalProperties: false, + }, }, - required: ['mode', 'docker', 'p2p', 'mempool', 'consensus', 'log', 'rpc', 'pprof', 'node', 'moniker', 'genesis', 'metrics'], + required: ['mode', 'docker', 'p2p', 'mempool', 'consensus', 'log', 'rpc', 'pprof', 'node', 'moniker', 'genesis', 'metrics', 'stateSync'], additionalProperties: false, }, }, diff --git a/packages/dashmate/templates/platform/drive/tenderdash/config.toml.dot b/packages/dashmate/templates/platform/drive/tenderdash/config.toml.dot index a818a356409..a3e9df5dd52 100644 --- a/packages/dashmate/templates/platform/drive/tenderdash/config.toml.dot +++ b/packages/dashmate/templates/platform/drive/tenderdash/config.toml.dot @@ -81,7 +81,7 @@ filter-peers = false # Example for routed multi-app setup: # abci = "routed" # address = "Info:socket:unix:///tmp/socket.1,Info:socket:unix:///tmp/socket.2,CheckTx:socket:unix:///tmp/socket.1,*:socket:unix:///tmp/socket.3" -address = "CheckTx:grpc:drive_abci:26670,*:socket:tcp://drive_abci:26658" +address = "ListSnapshots:grpc:drive_abci:26670,LoadSnapshotChunk:grpc:drive_abci:26670,CheckTx:grpc:drive_abci:26670,*:socket:tcp://drive_abci:26658" # Transport mechanism to connect to the ABCI application: socket | grpc | routed transport = "routed" # Maximum number of simultaneous connections to the ABCI application @@ -97,6 +97,10 @@ transport = "routed" #] grpc-concurrency = [ { "check_tx" = {{= it.platform.drive.tenderdash.mempool.maxConcurrentCheckTx }} }, + { "list_snapshots" = {{= it.platform.drive.tenderdash.stateSync.maxConcurrentListSnapshots }} }, + { "load_snapshot_chunk" = {{= it.platform.drive.tenderdash.stateSync.maxConcurrentSnapshotChunk }} }, + { "offer_snapshot" = 1 }, + { "apply_snapshot_chunk" = 1 }, ] @@ -414,29 +418,26 @@ ttl-num-blocks = {{=it.platform.drive.tenderdash.mempool.ttlNumBlocks}} # the network to take and serve state machine snapshots. State sync is not attempted if the node # has any local state (LastBlockHeight > 0). The node will have a truncated block history, # starting from the height of the snapshot. -enable = false +enable = {{= it.platform.drive.tenderdash.stateSync.enabled.toString() }} # State sync uses light client verification to verify state. This can be done either through the # P2P layer or RPC layer. Set this to true to use the P2P layer. If false (default), RPC layer # will be used. -use-p2p = false +use-p2p = true # If using RPC, at least two addresses need to be provided. They should be compatible with net.Dial, # for example: "host.example.com:2125" rpc-servers = "" -# The hash and height of a trusted block. Must be within the trust-period. -trust-height = 0 -trust-hash = "" - -# The trust period should be set so that Tendermint can detect and gossip misbehavior before -# it is considered expired. For chains based on the Cosmos SDK, one day less than the unbonding -# period should suffice. -trust-period = "168h0m0s" - # Time to spend discovering snapshots before initiating a restore. discovery-time = "15s" +# Number of times to retry state sync. When retries are exhausted, the node will +# fall back to the regular block sync. Set to 0 to disable retries. Default is 3. +# Note that in pessimistic case, it will take at least (discovery-time * retries) before +# falling back to block sync. +retries = {{= it.platform.drive.tenderdash.stateSync.retries }} + # Temporary directory for state sync snapshot chunks, defaults to os.TempDir(). # The synchronizer will create a new, randomly named directory within this directory # and remove it when the sync is complete. @@ -444,10 +445,10 @@ temp-dir = "" # The timeout duration before re-requesting a chunk, possibly from a different # peer (default: 15 seconds). -chunk-request-timeout = "15s" +chunk-request-timeout = "{{= it.platform.drive.tenderdash.stateSync.chunkRequestTimeout }}" # The number of concurrent chunk and block fetchers to run (default: 4). -fetchers = "4" +fetchers = "{{= it.platform.drive.tenderdash.stateSync.fetchersCount }}" ####################################################### ### Consensus Configuration Options ### diff --git a/packages/rs-dpp/src/lib.rs b/packages/rs-dpp/src/lib.rs index 66599277405..8ac1ec45bff 100644 --- a/packages/rs-dpp/src/lib.rs +++ b/packages/rs-dpp/src/lib.rs @@ -59,6 +59,7 @@ pub mod voting; pub mod core_types; pub mod group; +pub mod reduced_platform_state; pub mod withdrawal; pub use async_trait; diff --git a/packages/rs-dpp/src/reduced_platform_state/mod.rs b/packages/rs-dpp/src/reduced_platform_state/mod.rs new file mode 100644 index 00000000000..1420b00724e --- /dev/null +++ b/packages/rs-dpp/src/reduced_platform_state/mod.rs @@ -0,0 +1,41 @@ +use crate::serialization::{PlatformDeserializable, PlatformSerializable}; +use crate::ProtocolError; +use crate::{ + reduced_platform_state::v0::ReducedPlatformStateForSavingV0, + serialization::PlatformDeserializableFromVersionedStructure, +}; +use bincode::{Decode, Encode}; +use platform_version::version::PlatformVersion; + +pub mod v0; + +/// Reduced Platform State For Saving +#[derive(Clone, Debug, Encode, Decode)] +pub enum ReducedPlatformStateForSaving { + V0(ReducedPlatformStateForSavingV0), +} + +impl PlatformDeserializableFromVersionedStructure for ReducedPlatformStateForSaving { + fn versioned_deserialize( + data: &[u8], + _platform_version: &PlatformVersion, + ) -> Result + where + Self: Sized, + { + Ok(ReducedPlatformStateForSaving::V0( + ReducedPlatformStateForSavingV0::deserialize_from_bytes(data)?, + )) + } +} + +impl PlatformSerializable for ReducedPlatformStateForSaving { + type Error = crate::errors::ProtocolError; + + fn serialize_to_bytes(&self) -> Result, Self::Error> { + let bytes = match self { + ReducedPlatformStateForSaving::V0(v0) => v0.serialize_to_bytes()?, + }; + Ok(bytes) + } +} diff --git a/packages/rs-dpp/src/reduced_platform_state/v0/mod.rs b/packages/rs-dpp/src/reduced_platform_state/v0/mod.rs new file mode 100644 index 00000000000..495ecb86cef --- /dev/null +++ b/packages/rs-dpp/src/reduced_platform_state/v0/mod.rs @@ -0,0 +1,70 @@ +use crate::serialization::{PlatformDeserializable, PlatformSerializable}; +use crate::util::deserializer::ProtocolVersion; +use crate::ProtocolError; +use crate::{ + block::extended_block_info::ExtendedBlockInfo, + fee::default_costs::EpochIndexFeeVersionsForStorage, +}; +use bincode::{Decode, Encode}; +use platform_value::Bytes32; + +/// Reduced Platform State for Saving V0 +/// This minimal version of Platform state is written in GroveDB under the root hash. +/// This allows a freshly new synced node to reconstruct Platform state. +#[derive(Clone, Debug, Encode, Decode)] +pub struct ReducedPlatformStateForSavingV0 { + /// The last committed block info (at height `H-1`) + pub last_committed_block_info: Option, + /// Currently processed block info (at height `H`) + // pub current_block_info: ExtendedBlockInfo, + /// Current Version + pub current_protocol_version_in_consensus: ProtocolVersion, + /// upcoming protocol version + pub next_epoch_protocol_version: ProtocolVersion, + /// current quorum + pub current_validator_set_quorum_hash: Bytes32, + /// next quorum + pub next_validator_set_quorum_hash: Option, + /// previous Fee Versions + pub previous_fee_versions: EpochIndexFeeVersionsForStorage, + + /// ordered list of quorum hashes that reflect quorum positions + /// TODO: optimize this to not store the whole quorum hash, but only some index + pub quorum_positions: Vec>, + + /// Core chain locked height, as provided in RequestProcessProposal ABCI message; + /// note this can differ from the one in RequestPrepareProposal, as it can be modified by + /// proposer. + pub proposed_core_chain_locked_height: u32, +} + +impl PlatformSerializable for ReducedPlatformStateForSavingV0 { + type Error = crate::errors::ProtocolError; + + fn serialize_to_bytes(&self) -> Result, Self::Error> { + let config = bincode::config::standard(); + bincode::encode_to_vec(self, config).map_err(|e| { + ProtocolError::PlatformSerializationError(format!( + "cannot serialize ReducedPlatformStateForSavingV0: {}", + e + )) + }) + } +} + +impl PlatformDeserializable for ReducedPlatformStateForSavingV0 { + fn deserialize_from_bytes_no_limit(data: &[u8]) -> Result + where + Self: Sized, + { + let config = bincode::config::standard(); + bincode::decode_from_slice(data, config) + .map_err(|e| { + ProtocolError::PlatformDeserializationError(format!( + "cannot deserialize ReducedPlatformStateForSavingV0: {}", + e + )) + }) + .map(|(object, _)| object) + } +} diff --git a/packages/rs-drive-abci/.env.local b/packages/rs-drive-abci/.env.local index c0e3ac3347a..14e7d98c776 100644 --- a/packages/rs-drive-abci/.env.local +++ b/packages/rs-drive-abci/.env.local @@ -12,6 +12,16 @@ ABCI_LOG_STDOUT_FORMAT=pretty ABCI_LOG_STDOUT_COLOR=true DB_PATH=/tmp/db + +# State Sync +CHECKPOINTS_PATH=${DB_PATH}/checkpoints +SNAPSHOTS_ENABLED=false +SNAPSHOTS_FREQUENCY=5 +MAX_NUM_SNAPSHOTS=4 + +# GroveDB database file +GROVEDB_LATEST_FILE=${DB_PATH}/latest_state + REJECTIONS_PATH=/tmp/rejected # Cache size for Data Contracts diff --git a/packages/rs-drive-abci/.env.mainnet b/packages/rs-drive-abci/.env.mainnet index 65409c1d0a3..ed22c2f7128 100644 --- a/packages/rs-drive-abci/.env.mainnet +++ b/packages/rs-drive-abci/.env.mainnet @@ -14,6 +14,12 @@ ABCI_LOG_STDOUT_COLOR=true DB_PATH=/tmp/db REJECTIONS_PATH=/tmp/rejected +# State Sync +CHECKPOINTS_PATH=${DB_PATH}/checkpoints +SNAPSHOTS_ENABLED=false +SNAPSHOTS_FREQUENCY=20 +MAX_NUM_SNAPSHOTS=10 + # Cache size for Data Contracts DATA_CONTRACTS_GLOBAL_CACHE_SIZE=500 DATA_CONTRACTS_BLOCK_CACHE_SIZE=200 diff --git a/packages/rs-drive-abci/.env.testnet b/packages/rs-drive-abci/.env.testnet index dccf681adf6..dde497b57e8 100644 --- a/packages/rs-drive-abci/.env.testnet +++ b/packages/rs-drive-abci/.env.testnet @@ -14,6 +14,12 @@ ABCI_LOG_STDOUT_COLOR=true DB_PATH=/tmp/db REJECTIONS_PATH=/tmp/rejected +# State Sync +CHECKPOINTS_PATH=${DB_PATH}/checkpoints +SNAPSHOTS_ENABLED=false +SNAPSHOTS_FREQUENCY=5 +MAX_NUM_SNAPSHOTS=5 + # Cache size for Data Contracts DATA_CONTRACTS_GLOBAL_CACHE_SIZE=500 DATA_CONTRACTS_BLOCK_CACHE_SIZE=200 diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 33c32dffd11..1222407a087 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -54,6 +54,7 @@ tracing-subscriber = { version = "0.3.16", default-features = false, features = ], optional = false } tenderdash-abci = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.4.0", tag = "v1.4.0", features = [ "grpc", + "serde", ] } lazy_static = "1.4.0" @@ -79,6 +80,7 @@ async-trait = "0.1.77" console-subscriber = { version = "0.4", optional = true } bls-signatures = { git = "https://github.com/dashpay/bls-signatures", tag = "1.3.3", optional = true } + [dev-dependencies] bs58 = { version = "0.5.0" } base64 = "0.22.1" diff --git a/packages/rs-drive-abci/src/abci/app/check_tx.rs b/packages/rs-drive-abci/src/abci/app/check_tx.rs index 2f4a39c1b33..bd25f082093 100644 --- a/packages/rs-drive-abci/src/abci/app/check_tx.rs +++ b/packages/rs-drive-abci/src/abci/app/check_tx.rs @@ -1,7 +1,8 @@ -use crate::abci::app::PlatformApplication; +use crate::abci::app::{PlatformApplication, SnapshotManagerApplication}; use crate::abci::handler; use crate::error::Error; use crate::platform_types::platform::Platform; +use crate::platform_types::snapshot::SnapshotManager; use crate::rpc::core::CoreRPCLike; use crate::utils::spawn_blocking_task_with_name_if_supported; use async_trait::async_trait; @@ -22,6 +23,8 @@ where /// Platform platform: Arc>, core_rpc: Arc, + /// Snapshot manager + snapshot_manager: SnapshotManager, } impl PlatformApplication for CheckTxAbciApplication @@ -33,13 +36,31 @@ where } } +impl SnapshotManagerApplication for CheckTxAbciApplication +where + C: CoreRPCLike + Send + Sync + 'static, +{ + fn snapshot_manager(&self) -> &SnapshotManager { + &self.snapshot_manager + } +} + impl CheckTxAbciApplication where C: CoreRPCLike + Send + Sync + 'static, { /// Create new ABCI app pub fn new(platform: Arc>, core_rpc: Arc) -> Self { - Self { platform, core_rpc } + let snapshot_manager = SnapshotManager::new( + platform.config.abci.state_sync.checkpoints_path.clone(), + platform.config.abci.state_sync.max_num_snapshots, + platform.config.abci.state_sync.snapshots_frequency, + ); + Self { + platform, + core_rpc, + snapshot_manager, + } } } @@ -92,6 +113,24 @@ where .await .map_err(|error| tonic::Status::internal(format!("check tx panics: {}", error)))? } + + async fn list_snapshots( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + handler::list_snapshots(self, request.into_inner()) + .map(tonic::Response::new) + .map_err(|e| tonic::Status::internal(format!("list_snapshots failed: {}", e))) + } + + async fn load_snapshot_chunk( + &self, + request: tonic::Request, + ) -> Result, tonic::Status> { + handler::load_snapshot_chunk(self, request.into_inner()) + .map(tonic::Response::new) + .map_err(|e| tonic::Status::internal(format!("load_snapshot_chunk failed: {}", e))) + } } pub fn error_into_status(error: Error) -> tonic::Status { diff --git a/packages/rs-drive-abci/src/abci/app/consensus.rs b/packages/rs-drive-abci/src/abci/app/consensus.rs index d2145d1e4b0..dd3ae34f0da 100644 --- a/packages/rs-drive-abci/src/abci/app/consensus.rs +++ b/packages/rs-drive-abci/src/abci/app/consensus.rs @@ -1,10 +1,14 @@ -use crate::abci::app::{BlockExecutionApplication, PlatformApplication, TransactionalApplication}; +use crate::abci::app::{ + BlockExecutionApplication, PlatformApplication, SnapshotManagerApplication, + StateSyncApplication, TransactionalApplication, +}; use crate::abci::handler; use crate::abci::handler::error::error_into_exception; use crate::error::execution::ExecutionError; use crate::error::Error; use crate::execution::types::block_execution_context::BlockExecutionContext; use crate::platform_types::platform::Platform; +use crate::platform_types::snapshot::{SnapshotFetchingSession, SnapshotManager}; use crate::rpc::core::CoreRPCLike; use dpp::version::PlatformVersion; use drive::grovedb::Transaction; @@ -15,23 +19,35 @@ use tenderdash_abci::proto::abci as proto; /// AbciApp is an implementation of ABCI Application, as defined by Tenderdash. /// /// AbciApp implements logic that should be triggered when Tenderdash performs various operations, like -/// creating new proposal or finalizing new block. -pub struct ConsensusAbciApplication<'a, C> { +/// creating new proposal, finalizing new block, accept a new snapshot and process incoming chunks (state sync) +/// 'p: 'tx, means that Platform must outlive the transaction +pub struct ConsensusAbciApplication<'p, C> { /// Platform - platform: &'a Platform, + platform: &'p Platform, /// The current GroveDb transaction - transaction: RwLock>>, + transaction: RwLock>>, /// The current block execution context block_execution_context: RwLock>, + /// The State sync session + snapshot_fetching_session: RwLock>>, + /// The snapshot manager + snapshot_manager: SnapshotManager, } -impl<'a, C> ConsensusAbciApplication<'a, C> { +impl<'p, C> ConsensusAbciApplication<'p, C> { /// Create new ABCI app - pub fn new(platform: &'a Platform) -> Self { + pub fn new(platform: &'p Platform) -> Self { + let snapshot_manager = SnapshotManager::new( + platform.config.abci.state_sync.checkpoints_path.clone(), + platform.config.abci.state_sync.max_num_snapshots, + platform.config.abci.state_sync.snapshots_frequency, + ); Self { platform, transaction: Default::default(), block_execution_context: Default::default(), + snapshot_fetching_session: Default::default(), + snapshot_manager, } } } @@ -42,20 +58,36 @@ impl PlatformApplication for ConsensusAbciApplication<'_, C> { } } +impl SnapshotManagerApplication for ConsensusAbciApplication<'_, C> { + fn snapshot_manager(&self) -> &SnapshotManager { + &self.snapshot_manager + } +} + +impl<'p, C> StateSyncApplication<'p, C> for ConsensusAbciApplication<'p, C> { + fn snapshot_fetching_session(&self) -> &RwLock>> { + &self.snapshot_fetching_session + } + + fn platform(&self) -> &'p Platform { + self.platform + } +} + impl BlockExecutionApplication for ConsensusAbciApplication<'_, C> { fn block_execution_context(&self) -> &RwLock> { &self.block_execution_context } } -impl<'a, C> TransactionalApplication<'a> for ConsensusAbciApplication<'a, C> { +impl<'p, C> TransactionalApplication<'p> for ConsensusAbciApplication<'p, C> { /// create and store a new transaction fn start_transaction(&self) { let transaction = self.platform.drive.grove.start_transaction(); self.transaction.write().unwrap().replace(transaction); } - fn transaction(&self) -> &RwLock>> { + fn transaction(&self) -> &RwLock>> { &self.transaction } @@ -149,4 +181,18 @@ where ) -> Result { handler::verify_vote_extension(self, request).map_err(error_into_exception) } + + fn offer_snapshot( + &self, + request: proto::RequestOfferSnapshot, + ) -> Result { + handler::offer_snapshot(self, request).map_err(error_into_exception) + } + + fn apply_snapshot_chunk( + &self, + request: proto::RequestApplySnapshotChunk, + ) -> Result { + handler::apply_snapshot_chunk(self, request).map_err(error_into_exception) + } } diff --git a/packages/rs-drive-abci/src/abci/app/full.rs b/packages/rs-drive-abci/src/abci/app/full.rs index 542bce32668..353c4fefd8b 100644 --- a/packages/rs-drive-abci/src/abci/app/full.rs +++ b/packages/rs-drive-abci/src/abci/app/full.rs @@ -1,10 +1,14 @@ -use crate::abci::app::{BlockExecutionApplication, PlatformApplication, TransactionalApplication}; +use crate::abci::app::{ + BlockExecutionApplication, PlatformApplication, SnapshotManagerApplication, + StateSyncApplication, TransactionalApplication, +}; use crate::abci::handler; use crate::abci::handler::error::error_into_exception; use crate::error::execution::ExecutionError; use crate::error::Error; use crate::execution::types::block_execution_context::BlockExecutionContext; use crate::platform_types::platform::Platform; +use crate::platform_types::snapshot::{SnapshotFetchingSession, SnapshotManager}; use crate::rpc::core::CoreRPCLike; use dpp::version::PlatformVersion; use drive::grovedb::Transaction; @@ -23,15 +27,26 @@ pub struct FullAbciApplication<'a, C> { pub transaction: RwLock>>, /// The current block execution context pub block_execution_context: RwLock>, + /// The State sync session + pub snapshot_fetching_session: RwLock>>, + /// The snapshot manager + pub snapshot_manager: SnapshotManager, } impl<'a, C> FullAbciApplication<'a, C> { /// Create new ABCI app pub fn new(platform: &'a Platform) -> Self { + let snapshot_manager = SnapshotManager::new( + platform.config.abci.state_sync.checkpoints_path.clone(), + platform.config.abci.state_sync.max_num_snapshots, + platform.config.abci.state_sync.snapshots_frequency, + ); Self { platform, transaction: Default::default(), block_execution_context: Default::default(), + snapshot_fetching_session: Default::default(), + snapshot_manager, } } } @@ -42,6 +57,22 @@ impl PlatformApplication for FullAbciApplication<'_, C> { } } +impl SnapshotManagerApplication for FullAbciApplication<'_, C> { + fn snapshot_manager(&self) -> &SnapshotManager { + &self.snapshot_manager + } +} + +impl<'a, C> StateSyncApplication<'a, C> for FullAbciApplication<'a, C> { + fn snapshot_fetching_session(&self) -> &RwLock>> { + &self.snapshot_fetching_session + } + + fn platform(&self) -> &'a Platform { + self.platform + } +} + impl BlockExecutionApplication for FullAbciApplication<'_, C> { fn block_execution_context(&self) -> &RwLock> { &self.block_execution_context @@ -150,4 +181,32 @@ where ) -> Result { handler::verify_vote_extension(self, request).map_err(error_into_exception) } + + fn offer_snapshot( + &self, + request: proto::RequestOfferSnapshot, + ) -> Result { + handler::offer_snapshot(self, request).map_err(error_into_exception) + } + + fn apply_snapshot_chunk( + &self, + request: proto::RequestApplySnapshotChunk, + ) -> Result { + handler::apply_snapshot_chunk(self, request).map_err(error_into_exception) + } + + fn list_snapshots( + &self, + request: proto::RequestListSnapshots, + ) -> Result { + handler::list_snapshots(self, request).map_err(error_into_exception) + } + + fn load_snapshot_chunk( + &self, + request: proto::RequestLoadSnapshotChunk, + ) -> Result { + handler::load_snapshot_chunk(self, request).map_err(error_into_exception) + } } diff --git a/packages/rs-drive-abci/src/abci/app/mod.rs b/packages/rs-drive-abci/src/abci/app/mod.rs index d86290b566b..c5d1dcef036 100644 --- a/packages/rs-drive-abci/src/abci/app/mod.rs +++ b/packages/rs-drive-abci/src/abci/app/mod.rs @@ -10,6 +10,7 @@ pub mod execution_result; mod full; use crate::execution::types::block_execution_context::BlockExecutionContext; +use crate::platform_types::snapshot::{SnapshotFetchingSession, SnapshotManager}; use crate::rpc::core::DefaultCoreRPC; pub use check_tx::CheckTxAbciApplication; pub use consensus::ConsensusAbciApplication; @@ -22,13 +23,19 @@ pub trait PlatformApplication { fn platform(&self) -> &Platform; } +/// ABCI application supporting snapshot manager +pub trait SnapshotManagerApplication { + /// Returns Snapshot manager + fn snapshot_manager(&self) -> &SnapshotManager; +} + /// Transactional ABCI application -pub trait TransactionalApplication<'a> { +pub trait TransactionalApplication<'p> { /// Creates and keeps a new transaction fn start_transaction(&self); /// Returns the current transaction - fn transaction(&self) -> &RwLock>>; + fn transaction(&self) -> &RwLock>>; /// Commits created transaction fn commit_transaction(&self, platform_version: &PlatformVersion) -> Result<(), Error>; @@ -39,3 +46,12 @@ pub trait BlockExecutionApplication { /// Returns the current block execution context fn block_execution_context(&self) -> &RwLock>; } + +/// Application that can maintain state sync +pub trait StateSyncApplication<'p, C = DefaultCoreRPC> { + /// Returns the current snapshot fetching session + fn snapshot_fetching_session(&self) -> &RwLock>>; + + /// Returns platform reference + fn platform(&self) -> &'p Platform; +} diff --git a/packages/rs-drive-abci/src/abci/config.rs b/packages/rs-drive-abci/src/abci/config.rs index 62779edd6b7..a35ebf9d567 100644 --- a/packages/rs-drive-abci/src/abci/config.rs +++ b/packages/rs-drive-abci/src/abci/config.rs @@ -1,7 +1,8 @@ //! Configuration of ABCI Application server -use crate::utils::from_opt_str_or_number; +use crate::utils::{from_opt_str_or_number, from_str_or_number}; use serde::{Deserialize, Serialize}; +use std::path::PathBuf; // We allow changes in the ABCI configuration, but there should be a social process // involved in making this change. @@ -37,6 +38,10 @@ pub struct AbciConfig { /// Maximum time limit (in ms) to process state transitions to prepare proposal #[serde(default, deserialize_with = "from_opt_str_or_number")] pub proposer_tx_processing_time_limit: Option, + + /// State sync configuration + #[serde(flatten)] + pub state_sync: StateSyncAbciConfig, } impl AbciConfig { @@ -47,10 +52,22 @@ impl AbciConfig { pub(crate) fn default_genesis_core_height() -> u32 { 1 } -} -impl Default for AbciConfig { - fn default() -> Self { + /// Default ABCI configuration for mainnet + pub fn default_mainnet() -> Self { + Self { + consensus_bind_address: "tcp://127.0.0.1:1234".to_string(), + genesis_height: AbciConfig::default_genesis_height(), + genesis_core_height: AbciConfig::default_genesis_core_height(), + chain_id: "chain_id".to_string(), + log: Default::default(), + proposer_tx_processing_time_limit: Default::default(), + state_sync: StateSyncAbciConfig::default_mainnet(), + } + } + + /// Default ABCI configuration for local development + pub fn default_local() -> Self { Self { consensus_bind_address: "tcp://127.0.0.1:1234".to_string(), genesis_height: AbciConfig::default_genesis_height(), @@ -58,6 +75,86 @@ impl Default for AbciConfig { chain_id: "chain_id".to_string(), log: Default::default(), proposer_tx_processing_time_limit: Default::default(), + state_sync: StateSyncAbciConfig::default_local(), + } + } + + /// Default ABCI configuration for testnet + pub fn default_testnet() -> Self { + Self { + consensus_bind_address: "tcp://127.0.0.1:1234".to_string(), + genesis_height: AbciConfig::default_genesis_height(), + genesis_core_height: AbciConfig::default_genesis_core_height(), + chain_id: "chain_id".to_string(), + log: Default::default(), + proposer_tx_processing_time_limit: Default::default(), + state_sync: StateSyncAbciConfig::default_testnet(), + } + } +} + +impl Default for AbciConfig { + fn default() -> Self { + Self::default_mainnet() + } +} + +/// Configuration for StateSync feature +#[derive(Clone, Debug, Serialize, Deserialize)] +#[serde(default)] +pub struct StateSyncAbciConfig { + /// Enable snapshot + #[serde(deserialize_with = "from_str_or_number")] + pub snapshots_enabled: bool, + + /// Path to checkpoints + pub checkpoints_path: PathBuf, + + /// Frequency of snapshot creation (in blocks) + #[serde(deserialize_with = "from_str_or_number")] + pub snapshots_frequency: i64, + + /// Maximum number of snapshots to keep + #[serde(deserialize_with = "from_str_or_number")] + pub max_num_snapshots: usize, +} + +impl Default for StateSyncAbciConfig { + fn default() -> Self { + Self::default_local() + } +} + +#[allow(missing_docs)] +impl StateSyncAbciConfig { + pub fn default_local() -> Self { + Self { + snapshots_enabled: false, + checkpoints_path: Self::default_checkpoints_path(), + snapshots_frequency: 5, + max_num_snapshots: 5, + } + } + + pub fn default_testnet() -> Self { + Self { + snapshots_enabled: true, + checkpoints_path: Self::default_checkpoints_path(), + snapshots_frequency: 5, + max_num_snapshots: 5, } } + + pub fn default_mainnet() -> Self { + Self { + snapshots_enabled: true, + checkpoints_path: Self::default_checkpoints_path(), + snapshots_frequency: 5, + max_num_snapshots: 5, + } + } + + fn default_checkpoints_path() -> PathBuf { + PathBuf::from("/var/lib/dash-platform/data/checkpoints") + } } diff --git a/packages/rs-drive-abci/src/abci/error.rs b/packages/rs-drive-abci/src/abci/error.rs index 857321a16e8..56cd78deafd 100644 --- a/packages/rs-drive-abci/src/abci/error.rs +++ b/packages/rs-drive-abci/src/abci/error.rs @@ -54,6 +54,14 @@ pub enum AbciError { #[error("bad commit signature: {0}")] BadCommitSignature(String), + /// Client State sync bad request + #[error("bad request state sync: {0}")] + StateSyncBadRequest(String), + + /// Server State sync bad request + #[error("internal error state sync: {0}")] + StateSyncInternalError(String), + /// The chain lock received was invalid #[error("invalid chain lock: {0}")] InvalidChainLock(String), diff --git a/packages/rs-drive-abci/src/abci/handler/apply_snapshot_chunk.rs b/packages/rs-drive-abci/src/abci/handler/apply_snapshot_chunk.rs new file mode 100644 index 00000000000..fd633e66107 --- /dev/null +++ b/packages/rs-drive-abci/src/abci/handler/apply_snapshot_chunk.rs @@ -0,0 +1,704 @@ +use crate::abci::app::{SnapshotManagerApplication, StateSyncApplication}; +use crate::abci::AbciError; +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::execution::platform_events::core_based_updates::update_quorum_info::v0::QuorumSetType; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::v0::{PlatformStateV0, PlatformStateV0Methods}; +use crate::platform_types::platform_state::PlatformState; +use crate::platform_types::signature_verification_quorum_set::{ + SignatureVerificationQuorumSet, SignatureVerificationQuorumSetV0Methods, VerificationQuorum, +}; +use crate::platform_types::validator_set::v0::ValidatorSetMethodsV0; +use crate::rpc::core::CoreRPCLike; +use dashcore_rpc::dashcore::hashes::Hash; +use dashcore_rpc::dashcore_rpc_json::{ + ExtendedQuorumListResult, MasternodeListDiff, MasternodeType, QuorumType, +}; +use dpp::block::extended_block_info::v0::{ExtendedBlockInfoV0, ExtendedBlockInfoV0Getters}; +use dpp::block::extended_block_info::ExtendedBlockInfo; +use dpp::bls_signatures::PublicKey as BlsPublicKey; +use dpp::core_types::validator_set::v0::{ValidatorSetV0, ValidatorSetV0Getters}; +use dpp::core_types::validator_set::ValidatorSet as CoreValidatorSet; +use dpp::dashcore::BlockHash; +use dpp::reduced_platform_state::ReducedPlatformStateForSaving; +use dpp::version::fee::FeeVersion; +use dpp::version::PlatformVersion; +use indexmap::IndexMap; +use itertools::Itertools; +use std::collections::BTreeMap; +use std::sync::Arc; +use tenderdash_abci::proto::abci as proto; + +pub fn apply_snapshot_chunk<'a, 'db: 'a, A, C>( + app: &'a A, + request: proto::RequestApplySnapshotChunk, +) -> Result +where + A: SnapshotManagerApplication + StateSyncApplication<'db, C> + 'db, + C: CoreRPCLike + 'db, +{ + if tracing::enabled!(tracing::Level::TRACE) { + let chunk_id = if request.chunk_id.len() > 8 { + &(request.chunk_id[0..8]) + } else { + &request.chunk_id + }; + tracing::trace!( + chunk_id, + "[state_sync] api apply_snapshot_chunk chunk_id:{}", + hex::encode(chunk_id) + ); + } + + let platform_version = app.platform().state.load().current_platform_version()?; + + // Lock first the RwLock + let mut session_write_guard = app.snapshot_fetching_session().write().map_err(|_| { + AbciError::StateSyncInternalError( + "apply_snapshot_chunk unable to lock session (poisoned)".to_string(), + ) + })?; + { + let session = session_write_guard + .as_mut() + .ok_or(AbciError::StateSyncInternalError( + "apply_snapshot_chunk unable to lock session".to_string(), + ))?; + + let next_chunk_ids = session + .state_sync_info + .apply_chunk( + &request.chunk_id, + &request.chunk, + platform_version.drive_abci.state_sync.protocol_version, + &platform_version.drive.grove_version, + ) + .map_err(|e| { + tracing::error!( + chunk_id = ?request.chunk_id, + chunk = ?request.chunk, + "state_sync apply_chunk_error", + ); + AbciError::StateSyncInternalError(format!( + "apply_snapshot_chunk unable to apply chunk:{}", + e + )) + })?; + if !next_chunk_ids.is_empty() && session.state_sync_info.is_sync_completed() { + Err(AbciError::StateSyncInternalError( + "apply_snapshot_chunk sessions is completed but next_chunk_ids is not empty" + .to_string(), + ))?; + } + tracing::info!("state_sync completed"); + if !session.state_sync_info.is_sync_completed() { + return Ok(proto::ResponseApplySnapshotChunk { + result: proto::response_apply_snapshot_chunk::Result::Accept.into(), + refetch_chunks: vec![], // TODO: Check when this is needed + reject_senders: vec![], // TODO: Check when this is needed + next_chunks: next_chunk_ids, + }); + } + } + { + // State sync is completed, consume session and commit it + let session = session_write_guard + .take() + .ok_or(AbciError::StateSyncInternalError( + "apply_snapshot_chunk unable to lock session (poisoned)".to_string(), + ))?; + let state_sync_info = session.state_sync_info; + app.platform() + .drive + .grove + .commit_session(state_sync_info) + .map_err(|e| { + AbciError::StateSyncInternalError(format!( + "apply_snapshot_chunk unable to commit session: {}", + e + )) + })?; + tracing::trace!("[state_sync] state sync completed. verifying"); + let incorrect_hashes = app + .platform() + .drive + .grove + .verify_grovedb(None, true, false, &platform_version.drive.grove_version) + .map_err(|e| { + AbciError::StateSyncInternalError(format!( + "apply_snapshot_chunk unable to verify grovedb: {}", + e + )) + })?; + if !incorrect_hashes.is_empty() { + Err(AbciError::StateSyncInternalError(format!( + "apply_snapshot_chunk grovedb verification failed with {} incorrect hashes", + incorrect_hashes.len() + )))?; + } + + reconstruct_platform_state(app, session.app_hash.as_slice(), platform_version)?; + + let drive_app_hash = app + .platform() + .drive + .grove + .root_hash(None, &platform_version.drive.grove_version) + .map_err(|e| { + AbciError::StateSyncInternalError(format!( + "apply_snapshot_chunk unable to get app hash: {}", + e + )) + }) + .unwrap()?; + + if drive_app_hash.to_vec() != session.app_hash { + tracing::error!( + state_sync_app_hash = ?hex::encode(session.app_hash), + drive_app_hash = ?hex::encode(drive_app_hash), + "state_sync: grovedb verification failed with incorrect app hash" + ); + Err(AbciError::StateSyncInternalError(format!( + "apply_snapshot_chunk grovedb verification failed with incorrect app hash: {}", + hex::encode(drive_app_hash) + )))?; + } + + Ok(proto::ResponseApplySnapshotChunk { + result: proto::response_apply_snapshot_chunk::Result::CompleteSnapshot.into(), + refetch_chunks: vec![], + reject_senders: vec![], + next_chunks: vec![], + }) + } +} +/// Reconstructs the platform state from the snapshot data. +/// +/// ## Expected state +/// +/// Given that we run state sync using snapshots created at height H, we expect the following state of +/// the system before entering this function: +/// +/// 1. [Platform::::fetch_reduced_platform_state] returns platform state after processing majority of `run_block_proposal`, +/// with an exception to validator_set_update(). +fn reconstruct_platform_state<'a, 'db: 'a, A, C>( + app: &'a A, + app_hash: &[u8], + platform_version: &PlatformVersion, +) -> Result<(), Error> +where + A: SnapshotManagerApplication + StateSyncApplication<'db, C> + 'db, + C: CoreRPCLike + 'db, +{ + let config = &app.platform().config; + let platform = app.platform(); + let drive = &platform.drive; + + log_apphash(app.platform(), "begin of reconstruct_platform_state")?; + + let reduced_platform_state = + Platform::::fetch_reduced_platform_state(drive, None, platform_version)?.ok_or_else( + || AbciError::StateSyncInternalError("reduced_platform_state".to_string()), + )?; + + let saved = match reduced_platform_state { + ReducedPlatformStateForSaving::V0(v0) => v0, + }; + + // Restore platform state. + // + // Platform state is saved in [`Platform::run_block_proposal`], after executing validator rotation + // and before finalizing the block. + // + // At this point, we should have validator sets loaded for next height. + let mut platform_state = PlatformState::V0(PlatformStateV0 { + genesis_block_info: None, + last_committed_block_info: None, + current_protocol_version_in_consensus: saved.current_protocol_version_in_consensus, + next_epoch_protocol_version: saved.next_epoch_protocol_version, + current_validator_set_quorum_hash: BlockHash::from_byte_array( + saved.current_validator_set_quorum_hash.to_buffer(), + ), + next_validator_set_quorum_hash: saved + .next_validator_set_quorum_hash + .map(|x| BlockHash::from_byte_array(x.to_buffer())), + patched_platform_version: None, + validator_sets: Default::default(), + chain_lock_validating_quorums: SignatureVerificationQuorumSet::new( + &config.chain_lock, + PlatformVersion::get(saved.current_protocol_version_in_consensus)?, + )?, + instant_lock_validating_quorums: SignatureVerificationQuorumSet::new( + &config.instant_lock, + PlatformVersion::get(saved.current_protocol_version_in_consensus)?, + )?, + full_masternode_list: BTreeMap::new(), + hpmn_masternode_list: BTreeMap::new(), + previous_fee_versions: saved + .previous_fee_versions + .into_keys() + .map(|epoch_index| (epoch_index, FeeVersion::first())) + .collect(), + }); + // We need an ExtendedBlockInfoV0 with app_hash filled; we don't have it as we save during proposal processing + // TODO: we leave signature and block hash set to [0u8;32], implement them as Option<> to avoid misuse of not + // initialized values + let current_block_info: ExtendedBlockInfo = match saved.last_committed_block_info { + Some(ExtendedBlockInfo::V0(block_info)) => ExtendedBlockInfoV0 { + app_hash: app_hash.try_into().map_err(|_| { + AbciError::StateSyncBadRequest(format!( + "app_hash {:?} has invalid legth", + &app_hash + )) + })?, + ..block_info + } + .into(), + None => { + return Err(Error::from(AbciError::StateSyncInternalError( + "reduced_platform_state: last_committed_block_info must be set".to_string(), + ))) + } + }; + + log_apphash(app.platform(), "before update_core_info")?; + + // Update the masternode list and create masternode identities and also update the active quorums + let transaction = drive.grove.start_transaction(); + app.platform().update_core_info( + None, + &mut platform_state, + saved.proposed_core_chain_locked_height, // new one, to be used in currently finalized block + true, + current_block_info.basic_info(), + &transaction, + platform_version, + )?; + + log_apphash(app.platform(), "before sort_quorums")?; + sort_quorums(platform_state.validator_sets_mut(), &saved.quorum_positions); + + let block_height = platform_state.last_committed_block_height(); + + log_apphash(app.platform(), "before store_platform_state")?; + platform.store_platform_state(&platform_state, Some(&transaction), platform_version)?; + + log_apphash(app.platform(), "before update_state_cache")?; + + // Now, we must advance to new height in state + + platform.update_state_cache( + current_block_info, + platform_state, + &transaction, + platform_version, + )?; + + // platform.state.store(Arc::new(platform_state)); + + log_apphash(app.platform(), "before commit_transaction")?; + drive + .grove + .commit_transaction(transaction) + .map_err(|e| { + AbciError::StateSyncInternalError(format!( + "apply_snapshot_chunk unable to commit transaction: {}", + e + )) + }) + .value?; + + if tracing::enabled!(tracing::Level::TRACE) { + let platform_state_for_logging = platform.state.load(); + tracing::trace!(block_height, platform_state = ?platform_state_for_logging, "state_sync_finalize"); + } + + log_apphash(app.platform(), "at the end of reconstruct_platform_state")?; + + Ok(()) +} + +/// Logs the application hash of the platform state and returns it. +fn log_apphash<'db, C>(platform: &Platform, desc: &str) -> Result<[u8; 32], Error> +where + C: CoreRPCLike + 'db, +{ + let grove_version = &platform + .state + .load() + .current_platform_version() + .unwrap() + .drive + .grove_version; + + let app_hash = platform + .drive + .grove + .root_hash(None, grove_version) + .unwrap()?; + + tracing::trace!( + app_ash = ?hex::encode(app_hash), + "state_sync: app hash {}", desc, + ); + + Ok(app_hash) +} + +fn build_masternode_lists<'a, 'db: 'a, A, C: 'db>( + app: &'a A, + platform_state: &mut PlatformState, + core_block_height: u32, +) -> Result<(), Error> +where + A: SnapshotManagerApplication + StateSyncApplication<'db, C> + 'db, + C: CoreRPCLike, +{ + let mn_list_diff = app + .platform() + .core_rpc + .get_protx_diff_with_masternodes(Some(1), core_block_height)?; + + let MasternodeListDiff { added_mns, .. } = &mn_list_diff; + + let added_hpmns = added_mns.iter().filter_map(|masternode| { + if masternode.node_type == MasternodeType::Evo { + Some((masternode.pro_tx_hash, masternode.clone())) + } else { + None + } + }); + + let added_masternodes = added_mns + .iter() + .map(|masternode| (masternode.pro_tx_hash, masternode.clone())); + + platform_state + .full_masternode_list_mut() + .extend(added_masternodes); + platform_state + .hpmn_masternode_list_mut() + .extend(added_hpmns); + + Ok(()) +} + +fn build_quorum_verification_set<'a, 'db: 'a, A, C: 'db>( + app: &'a A, + extended_quorum_list: &ExtendedQuorumListResult, + quorum_set_type: QuorumSetType, + quorum_set: &mut SignatureVerificationQuorumSet, +) -> Result<(), Error> +where + A: SnapshotManagerApplication + StateSyncApplication<'db, C> + 'db, + C: CoreRPCLike, +{ + let quorums_list: BTreeMap<_, _> = extended_quorum_list + .quorums_by_type + .get(&quorum_set_type.quorum_type()) + .ok_or(Error::Execution(ExecutionError::DashCoreBadResponseError( + format!( + "expected quorums {}, but did not receive any from Dash Core", + quorum_set_type + ), + )))? + .iter() + .map(|(quorum_hash, extended_quorum_details)| { + (quorum_hash, extended_quorum_details.quorum_index) + }) + .collect(); + + // Fetch quorum info and their keys from the RPC for new quorums + // and then create VerificationQuorum instances + let new_quorums = quorums_list + .into_iter() + .map(|(quorum_hash, index)| { + let quorum_info = app.platform().core_rpc.get_quorum_info( + quorum_set_type.quorum_type(), + quorum_hash, + None, + )?; + + let public_key = match BlsPublicKey::try_from(quorum_info.quorum_public_key.as_slice()) + .map_err(ExecutionError::BlsErrorFromDashCoreResponse) + { + Ok(public_key) => public_key, + Err(e) => return Err(e.into()), + }; + + Ok((*quorum_hash, VerificationQuorum { public_key, index })) + }) + .collect::, Error>>()?; + + quorum_set.current_quorums_mut().extend(new_quorums); + + Ok(()) +} + +fn build_validators_list<'a, 'db: 'a, A, C: 'db>( + app: &'a A, + platform_state: &mut PlatformState, + extended_quorum_list: &mut ExtendedQuorumListResult, + quorums_order: &Vec>, + validator_set_quorum_type: QuorumType, +) -> Result<(), Error> +where + A: SnapshotManagerApplication + StateSyncApplication<'db, C> + 'db, + C: CoreRPCLike, +{ + let validator_quorums_list: BTreeMap<_, _> = extended_quorum_list + .quorums_by_type + .remove(&validator_set_quorum_type) + .ok_or(Error::Execution(ExecutionError::DashCoreBadResponseError( + format!( + "expected quorums of type {}, but did not receive any from Dash Core", + validator_set_quorum_type + ), + )))? + .into_iter() + .collect(); + + // Fetch quorum info and their keys from the RPC for new quorums + let mut quorum_infos = validator_quorums_list + .into_keys() + .map(|key| { + let quorum_info_result = + app.platform() + .core_rpc + .get_quorum_info(validator_set_quorum_type, &key, None)?; + Ok((key, quorum_info_result)) + }) + .collect::, Error>>()?; + + // Sort by height and then by hash + quorum_infos.sort_by(|a, b| { + let height_cmp = a.1.height.cmp(&b.1.height); + if height_cmp == std::cmp::Ordering::Equal { + a.0.cmp(&b.0) // Compare hashes if heights are equal + } else { + height_cmp + } + }); + + // Map to validator sets + let mut new_validator_sets = quorum_infos + .into_iter() + .map(|(quorum_hash, info_result)| { + let validator_set = CoreValidatorSet::V0(ValidatorSetV0::try_from_quorum_info_result( + info_result, + &platform_state, + )?); + Ok((quorum_hash, validator_set)) + }) + .collect::, Error>>()?; + + // Validator sets generated by previous algorithm, just to double-check + + let old_validator_sets = old_sort_quorums(new_validator_sets.clone()) + .into_iter() + .collect::>(); + /* + sort_quorums(&mut new_validator_sets, quorums_order); + */ + platform_state + .validator_sets_mut() + .extend(new_validator_sets.clone()); + + if !new_validator_sets.eq(&old_validator_sets) { + let new_vals = new_validator_sets + .iter() + .enumerate() + .map(|(i, (hash, _))| format!("{}=>{}", i, hex::encode(hash))) + .collect::>() + .join(", "); + + let old_vals = old_validator_sets + .iter() + .enumerate() + .map(|(i, (hash, _))| format!("{}=>{}", i, hex::encode(hash))) + .collect::>() + .join(", "); + + tracing::debug!( + new_validator_sets = new_vals, + old_validator_sets = old_vals, + "state_sync: validator sets sort gives different order" + ); + }; + // end of old valset check + + Ok(()) +} + +// Old sorting function, only for testing +// TODO: only for testing, all that old_validator_sets should be removed when new algorithm is stable +fn old_sort_quorums( + valsets: Vec<(BlockHash, CoreValidatorSet)>, +) -> IndexMap { + let mut old_valset_indexmap: IndexMap = IndexMap::new(); + old_valset_indexmap.extend(valsets); + + // Sort all validator sets into deterministic order by core block height of creation + old_valset_indexmap.sort_by(|_, quorum_a, _, quorum_b| { + let primary_comparison = quorum_b.core_height().cmp(&quorum_a.core_height()); + if primary_comparison == std::cmp::Ordering::Equal { + quorum_b + .quorum_hash() + .cmp(quorum_a.quorum_hash()) + .then_with(|| quorum_b.core_height().cmp(&quorum_a.core_height())) + } else { + primary_comparison + } + }); + + old_valset_indexmap +} +/// Ensure quorums are in the order described by `order`. +/// +/// Modifies `quorums` in place. +fn sort_quorums(quorums: &mut IndexMap, order: &[Vec]) { + let lookup_table = BTreeMap::from_iter(order.iter().enumerate().map(|x| (x.1 as &[u8], x.0))); + + quorums.sort_by(|a, _, b, _| { + let a_hash = a.as_byte_array().as_slice(); + let b_hash = b.as_byte_array().as_slice(); + + let a_index = lookup_table.get(a_hash).unwrap_or(&usize::MAX); + let b_index = lookup_table.get(b_hash).unwrap_or(&usize::MAX); + + a_index.cmp(b_index) + }); + // let ordered = order + // .iter() + // .map(|quorum_hash| { + // let (key, value) = quorums + // .iter() + // .find(|(hash, _)| hash.to_byte_array().as_slice() == quorum_hash) + // .ok_or(Error::Execution(ExecutionError::DashCoreBadResponseError( + // format!( + // "expected quorum {} not found in the list", + // hex::encode(quorum_hash) + // ), + // )))?; + + // Result::<_, Error>::Ok((*key, value.clone())) + // // key + // }) + // .collect::>()?; +} + +fn update_validators_list<'a, 'db: 'a, A, C: 'db>( + app: &'a A, + platform_state: &mut PlatformState, + proposer_pro_tx_hash: [u8; 32], +) -> Result<(), Error> +where + A: SnapshotManagerApplication + StateSyncApplication<'db, C> + 'db, + C: CoreRPCLike, +{ + let mut perform_rotation = false; + + if let Some(validator_set) = platform_state + .validator_sets() + .get(&platform_state.current_validator_set_quorum_hash()) + { + if let Some((last_member_pro_tx_hash, _)) = validator_set.members().last_key_value() { + // we should also perform a rotation if the validator set went through all quorum members + // this means we are at the last member of the quorum + if last_member_pro_tx_hash.as_byte_array() == &proposer_pro_tx_hash { + perform_rotation = true; + } + } else { + // the validator set has no members, very weird, but let's just perform a rotation + perform_rotation = true; + } + + // We should also perform a rotation if there are more than one quorum in the system + // and that the new proposer is on the same quorum and the last proposer but is before + // them in the list of proposers. + // This only works if Tenderdash goes through proposers properly + if &platform_state.last_committed_quorum_hash() + == platform_state + .current_validator_set_quorum_hash() + .as_byte_array() + && platform_state.last_committed_block_proposer_pro_tx_hash() > proposer_pro_tx_hash + && platform_state.validator_sets().len() > 1 + { + // 1 - We haven't changed quorums + // 2 - The new proposer is before the old proposer + // 3 - There are more than one quorum in the system + perform_rotation = true; + } + } else { + // we also need to perform a rotation if the validator set is being removed + perform_rotation = true; + } + + //todo: (maybe) perform a rotation if quorum health is low + + if perform_rotation { + // get the index of the previous quorum + let mut index = platform_state + .validator_sets() + .get_index_of(&platform_state.current_validator_set_quorum_hash()) + .ok_or(Error::Execution(ExecutionError::CorruptedCachedState( + format!("perform_rotation: current validator set quorum hash {} not in current known validator sets [{}] processing block {}", platform_state.current_validator_set_quorum_hash(), platform_state + .validator_sets().keys().map(|quorum_hash| quorum_hash.to_string()).join(" | "), + platform_state.last_committed_block_height() + 1, + ))))?; + // we should rotate the quorum + let quorum_count = platform_state.validator_sets().len(); + match quorum_count { + 0 => Err(Error::Execution(ExecutionError::CorruptedCachedState( + "no current quorums".to_string(), + ))), + 1 => Ok(()), // no rotation as we are the only quorum + count => { + let start_index = index; + let oldest_quorum_index_we_can_go_to = if count > 10 { + // if we have a lot of quorums (like on testnet and mainnet) + // we shouldn't start using the last ones as they could cycle out + count - 2 + } else { + count + }; + index = if index + 1 >= oldest_quorum_index_we_can_go_to { + 0 + } else { + index + 1 + }; + // We can't just take the next item because it might no longer be in the state + for _i in 0..oldest_quorum_index_we_can_go_to { + let (quorum_hash, _) = platform_state + .validator_sets() + .get_index(index) + .expect("expected next validator set"); + + // We still have it in the state + if let Some(new_validator_set) = + platform_state.validator_sets().get(quorum_hash) + { + platform_state.set_current_validator_set_quorum_hash(*quorum_hash); + return Ok(()); + } + index = (index + 1) % oldest_quorum_index_we_can_go_to; + if index == start_index { + break; + } + } + // All quorums changed + if let Some((quorum_hash, new_validator_set)) = + platform_state.validator_sets().first() + { + let new_quorum_hash = *quorum_hash; + platform_state.set_current_validator_set_quorum_hash(new_quorum_hash); + return Ok(()); + } + Ok(()) + } + } + } else { + Ok(()) + } +} diff --git a/packages/rs-drive-abci/src/abci/handler/finalize_block.rs b/packages/rs-drive-abci/src/abci/handler/finalize_block.rs index 852f85cc6b8..c8355faaff1 100644 --- a/packages/rs-drive-abci/src/abci/handler/finalize_block.rs +++ b/packages/rs-drive-abci/src/abci/handler/finalize_block.rs @@ -1,4 +1,7 @@ -use crate::abci::app::{BlockExecutionApplication, PlatformApplication, TransactionalApplication}; +use crate::abci::app::{ + BlockExecutionApplication, PlatformApplication, SnapshotManagerApplication, + TransactionalApplication, +}; use crate::error::execution::ExecutionError; use crate::error::Error; use crate::execution::types::block_execution_context::v0::BlockExecutionContextV0Getters; @@ -14,7 +17,10 @@ pub fn finalize_block<'a, A, C>( request: proto::RequestFinalizeBlock, ) -> Result where - A: PlatformApplication + TransactionalApplication<'a> + BlockExecutionApplication, + A: PlatformApplication + + SnapshotManagerApplication + + TransactionalApplication<'a> + + BlockExecutionApplication, C: CoreRPCLike, { let _timer = crate::metrics::abci_request_duration("finalize_block"); @@ -96,5 +102,28 @@ where .committed_block_height_guard .store(block_height, Ordering::Relaxed); + if app.platform().config.abci.state_sync.snapshots_enabled { + app.snapshot_manager() + .create_snapshot(&app.platform().drive.grove, block_height as i64) + .map_err(|e| { + Error::Execution(ExecutionError::CorruptedDriveResponse(format!( + "Unable to create snapshot:{}", + e + ))) + })?; + } + + if tracing::enabled!(tracing::Level::TRACE) { + let platform_state = app.platform().state.load(); + + let block_height = platform_state.last_committed_block_height(); + + tracing::trace!( + block_height, + platform_state = ?platform_state, + "state_finalize_block" + ); + } + Ok(proto::ResponseFinalizeBlock { retain_height: 0 }) } diff --git a/packages/rs-drive-abci/src/abci/handler/info.rs b/packages/rs-drive-abci/src/abci/handler/info.rs index 9ac9d316267..a8dbed5d8e9 100644 --- a/packages/rs-drive-abci/src/abci/handler/info.rs +++ b/packages/rs-drive-abci/src/abci/handler/info.rs @@ -22,6 +22,16 @@ where let platform_state = app.platform().state.load(); + let block_height = platform_state.last_committed_block_height(); + + if tracing::enabled!(tracing::Level::TRACE) { + tracing::trace!( + block_height, + platform_state = ?platform_state, + "state_info" + ); + } + let last_block_height = platform_state.last_committed_block_height() as i64; // Verify that Platform State corresponds to Drive commited state diff --git a/packages/rs-drive-abci/src/abci/handler/list_snapshots.rs b/packages/rs-drive-abci/src/abci/handler/list_snapshots.rs new file mode 100644 index 00000000000..9744d98cacb --- /dev/null +++ b/packages/rs-drive-abci/src/abci/handler/list_snapshots.rs @@ -0,0 +1,48 @@ +use crate::abci::app::{PlatformApplication, SnapshotManagerApplication}; +use crate::abci::handler::error::error_into_exception; +use crate::abci::AbciError; +use crate::error::Error; +use crate::platform_types::snapshot::Snapshot; +use crate::rpc::core::CoreRPCLike; +use drive::grovedb::GroveDb; +use std::path::Path; +use tenderdash_abci::proto::abci as proto; + +pub fn list_snapshots( + app: &A, + _: proto::RequestListSnapshots, +) -> Result +where + A: SnapshotManagerApplication + PlatformApplication, + C: CoreRPCLike, +{ + println!("[state_sync] api list_snapshots called"); + tracing::trace!("[state_sync] api list_snapshots called"); + let snapshots = app + .snapshot_manager() + .get_snapshots(&*app.platform().drive.grove) + .map_err(|e| { + AbciError::StateSyncInternalError(format!( + "list_snapshots unable to get snapshots: {}", + e + )) + })?; + + let mut response: proto::ResponseListSnapshots = Default::default(); + let convert_snapshots = |s: Snapshot| -> proto::Snapshot { + proto::Snapshot { + height: s.height as u64, + version: s.version as u32, + hash: s.hash.to_vec(), + metadata: s.metadata, + } + }; + let checkpoint_exists = |s: &Snapshot| -> bool { Path::new(&s.path).exists() }; + + response.snapshots = snapshots + .into_iter() + .filter(checkpoint_exists) + .map(convert_snapshots) + .collect(); + Ok(response) +} diff --git a/packages/rs-drive-abci/src/abci/handler/load_snapshot_chunk.rs b/packages/rs-drive-abci/src/abci/handler/load_snapshot_chunk.rs new file mode 100644 index 00000000000..5cf2db294ee --- /dev/null +++ b/packages/rs-drive-abci/src/abci/handler/load_snapshot_chunk.rs @@ -0,0 +1,58 @@ +use crate::abci::app::{PlatformApplication, SnapshotManagerApplication}; +use crate::abci::AbciError; +use crate::error::Error; +use crate::rpc::core::CoreRPCLike; +use bincode::{Decode, Encode}; +use dpp::version::PlatformVersion; +use drive::grovedb::GroveDb; +use tenderdash_abci::proto::abci as proto; + +pub fn load_snapshot_chunk( + app: &A, + request: proto::RequestLoadSnapshotChunk, +) -> Result +where + A: SnapshotManagerApplication + PlatformApplication, + C: CoreRPCLike, +{ + tracing::trace!( + "[state_sync] api load_snapshot_chunk height:{} chunk_id:{}", + request.height, + hex::encode(&request.chunk_id) + ); + let matched_snapshot = app + .snapshot_manager() + .get_snapshot_at_height(&app.platform().drive.grove, request.height as i64) + .map_err(|_| { + AbciError::StateSyncInternalError( + "load_snapshot_chunk failed: error matched snapshot".to_string(), + ) + })? + .ok_or_else(|| { + AbciError::StateSyncInternalError( + "load_snapshot_chunk failed: empty matched snapshot".to_string(), + ) + })?; + let db = GroveDb::open(&matched_snapshot.path).map_err(|e| { + AbciError::StateSyncInternalError(format!( + "load_snapshot_chunk failed: error opening grove:{}", + e + )) + })?; + let chunk = db + .fetch_chunk( + &request.chunk_id, + None, + request.version as u16, + &PlatformVersion::latest().drive.grove_version, + ) + .map_err(|e| { + AbciError::StateSyncInternalError(format!( + "load_snapshot_chunk failed: error fetching chunk{}", + e + )) + })?; + + let response = proto::ResponseLoadSnapshotChunk { chunk }; + Ok(response) +} diff --git a/packages/rs-drive-abci/src/abci/handler/mod.rs b/packages/rs-drive-abci/src/abci/handler/mod.rs index 8acd0737ebe..443758734a3 100644 --- a/packages/rs-drive-abci/src/abci/handler/mod.rs +++ b/packages/rs-drive-abci/src/abci/handler/mod.rs @@ -35,6 +35,7 @@ //! can only make changes that are backwards compatible. Otherwise new calls must be made instead. //! +mod apply_snapshot_chunk; mod check_tx; mod echo; pub mod error; @@ -42,16 +43,23 @@ mod extend_vote; mod finalize_block; mod info; mod init_chain; +mod list_snapshots; +mod load_snapshot_chunk; +mod offer_snapshot; mod prepare_proposal; mod process_proposal; mod verify_vote_extension; +pub use apply_snapshot_chunk::apply_snapshot_chunk; pub use check_tx::check_tx; pub use echo::echo; pub use extend_vote::extend_vote; pub use finalize_block::finalize_block; pub use info::info; pub use init_chain::init_chain; +pub use list_snapshots::list_snapshots; +pub use load_snapshot_chunk::load_snapshot_chunk; +pub use offer_snapshot::offer_snapshot; pub use prepare_proposal::prepare_proposal; pub use process_proposal::process_proposal; pub use verify_vote_extension::verify_vote_extension; diff --git a/packages/rs-drive-abci/src/abci/handler/offer_snapshot.rs b/packages/rs-drive-abci/src/abci/handler/offer_snapshot.rs new file mode 100644 index 00000000000..2cd494f2742 --- /dev/null +++ b/packages/rs-drive-abci/src/abci/handler/offer_snapshot.rs @@ -0,0 +1,114 @@ +use crate::abci::app::{SnapshotManagerApplication, StateSyncApplication}; +use crate::abci::AbciError; +use crate::error::Error; +use crate::platform_types::platform_state::v0::PlatformStateV0Methods; +use crate::platform_types::snapshot::SnapshotFetchingSession; +use dpp::version::PlatformVersion; +use tenderdash_abci::proto::abci as proto; +use tenderdash_abci::proto::abci::response_offer_snapshot; + +const SUBTREES_BATCH_SIZE: usize = 64; + +pub fn offer_snapshot<'a, 'db: 'a, A, C: 'db>( + app: &'a A, + request: proto::RequestOfferSnapshot, +) -> Result +where + A: SnapshotManagerApplication + StateSyncApplication<'db, C> + 'db, +{ + let request_app_hash: [u8; 32] = request.app_hash.try_into().map_err(|_| { + AbciError::StateSyncBadRequest("offer_snapshot invalid app_hash length".to_string()) + })?; + let offered_snapshot = request.snapshot.ok_or(AbciError::StateSyncBadRequest( + "offer_snapshot empty snapshot in request".to_string(), + ))?; + tracing::trace!( + "[state_sync] api offer_snapshot height:{}", + offered_snapshot.height + ); + + let platform_version = app.platform().state.load().current_platform_version()?; + + let mut session_write_guard = app.snapshot_fetching_session().write().map_err(|_| { + AbciError::StateSyncInternalError( + "offer_snapshot unable to lock session (poisoned)".to_string(), + ) + })?; + if session_write_guard.is_none() { + // No session currently, start a new one. + app.platform().drive.grove.wipe().map_err(|e| { + AbciError::StateSyncInternalError(format!( + "offer_snapshot unable to wipe grovedb:{}", + e + )) + })?; + let state_sync_info = app + .platform() + .drive + .grove + .start_snapshot_syncing( + request_app_hash, + SUBTREES_BATCH_SIZE, + platform_version.drive_abci.state_sync.protocol_version, + &platform_version.drive.grove_version, + ) + .map_err(|e| { + AbciError::StateSyncInternalError(format!( + "offer_snapshot unable to start snapshot syncing session:{}", + e + )) + })?; + let session = SnapshotFetchingSession::new( + offered_snapshot, + request_app_hash.to_vec(), + state_sync_info, + ); + *session_write_guard = Some(session); + let mut response = proto::ResponseOfferSnapshot::default(); + response.result = i32::from(response_offer_snapshot::Result::Accept); + Ok(response) + } else { + // Already syncing another snapshot session + let session = session_write_guard + .as_mut() + .ok_or(AbciError::StateSyncInternalError( + "offer_snapshot unable to lock session".to_string(), + ))?; + tracing::warn!( + "[state_sync] api offer_snapshot already syncing height:{}", + session.snapshot.height + ); + if offered_snapshot.height < session.snapshot.height { + return Err(Error::Abci(AbciError::StateSyncBadRequest( + "offer_snapshot already syncing newest height".to_string(), + ))); + } + app.platform().drive.grove.wipe().map_err(|e| { + AbciError::StateSyncInternalError(format!( + "offer_snapshot unable to wipe grovedb:{}", + e + )) + })?; + let state_sync_info = app + .platform() + .drive + .grove + .start_snapshot_syncing( + request_app_hash, + SUBTREES_BATCH_SIZE, + platform_version.drive_abci.state_sync.protocol_version, + &platform_version.drive.grove_version, + ) + .map_err(|e| { + AbciError::StateSyncInternalError(format!( + "offer_snapshot unable to start snapshot syncing session:{}", + e + )) + })?; + session.snapshot = offered_snapshot; + session.app_hash = request_app_hash.to_vec(); + session.state_sync_info = state_sync_info; + let response = proto::ResponseOfferSnapshot::default(); + Ok(response) + } +} diff --git a/packages/rs-drive-abci/src/abci/handler/prepare_proposal.rs b/packages/rs-drive-abci/src/abci/handler/prepare_proposal.rs index 61f58a01960..9c475f697c0 100644 --- a/packages/rs-drive-abci/src/abci/handler/prepare_proposal.rs +++ b/packages/rs-drive-abci/src/abci/handler/prepare_proposal.rs @@ -291,7 +291,7 @@ where failed_tx_count, storage_fees, processing_fees, - "Prepared proposal with {} transition{} for height: {}, round: {} in {} ms", + "Prepared proposal with {} transition {} for height: {}, round: {} in {} ms", valid_tx_count + invalid_paid_tx_count, if valid_tx_count + invalid_paid_tx_count > 0 { "s" diff --git a/packages/rs-drive-abci/src/config.rs b/packages/rs-drive-abci/src/config.rs index 73f9b69fc1f..3f0c4a8c994 100644 --- a/packages/rs-drive-abci/src/config.rs +++ b/packages/rs-drive-abci/src/config.rs @@ -723,7 +723,7 @@ impl PlatformConfig { }, block_spacing_ms: 5000, drive: Default::default(), - abci: Default::default(), + abci: AbciConfig::default_local(), core: Default::default(), execution: Default::default(), db_path: PathBuf::from("/var/lib/dash-platform/data"), @@ -765,7 +765,7 @@ impl PlatformConfig { }, block_spacing_ms: 5000, drive: Default::default(), - abci: Default::default(), + abci: AbciConfig::default_testnet(), core: Default::default(), execution: Default::default(), db_path: PathBuf::from("/var/lib/dash-platform/data"), @@ -807,7 +807,7 @@ impl PlatformConfig { }, block_spacing_ms: 5000, drive: DriveConfig::default_testnet(), - abci: Default::default(), + abci: AbciConfig::default_testnet(), core: Default::default(), execution: Default::default(), db_path: PathBuf::from("/var/lib/dash-platform/data"), @@ -849,7 +849,7 @@ impl PlatformConfig { }, block_spacing_ms: 5000, drive: Default::default(), - abci: Default::default(), + abci: AbciConfig::default_mainnet(), core: Default::default(), execution: Default::default(), db_path: PathBuf::from("/var/lib/dash-platform/data"), diff --git a/packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs b/packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs index 43712c7febd..de15d89a861 100644 --- a/packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs +++ b/packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs @@ -15,6 +15,7 @@ use dpp::version::PlatformVersion; use drive::grovedb::Transaction; mod v0; +mod v1; impl Platform where @@ -161,6 +162,16 @@ Your software version: {}, latest supported protocol version: {}."#, block_platform_version, timer, ), + 1 => self.run_block_proposal_v1( + block_proposal, + known_from_us, + epoch_info, + transaction, + platform_state, + block_platform_state, + block_platform_version, + timer, + ), version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { method: "run_block_proposal".to_string(), known_versions: vec![0], diff --git a/packages/rs-drive-abci/src/execution/engine/run_block_proposal/v1/mod.rs b/packages/rs-drive-abci/src/execution/engine/run_block_proposal/v1/mod.rs new file mode 100644 index 00000000000..7a700fba94a --- /dev/null +++ b/packages/rs-drive-abci/src/execution/engine/run_block_proposal/v1/mod.rs @@ -0,0 +1,438 @@ +use dpp::block::epoch::Epoch; +use dpp::block::extended_block_info::v0::ExtendedBlockInfoV0; +use dpp::validation::ValidationResult; +use drive::error::Error::GroveDB; + +use dpp::version::PlatformVersion; +use drive::grovedb::Transaction; + +use crate::abci::AbciError; +use crate::error::execution::ExecutionError; + +use crate::error::Error; +use crate::execution::types::block_execution_context::v0::{ + BlockExecutionContextV0Getters, BlockExecutionContextV0MutableGetters, +}; +use crate::execution::types::block_execution_context::BlockExecutionContext; +use crate::execution::types::block_fees::v0::BlockFeesV0; +use crate::execution::types::block_state_info::v0::{ + BlockStateInfoV0Getters, BlockStateInfoV0Methods, BlockStateInfoV0Setters, +}; +use crate::execution::types::{block_execution_context, block_state_info}; +use crate::metrics::HistogramTiming; +use crate::platform_types::block_execution_outcome; +use crate::platform_types::block_proposal; +use crate::platform_types::epoch_info::v0::{EpochInfoV0Getters, EpochInfoV0Methods}; +use crate::platform_types::epoch_info::EpochInfo; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::v0::PlatformStateV0Methods; +use crate::platform_types::platform_state::PlatformState; +use crate::platform_types::verify_chain_lock_result::v0::VerifyChainLockResult; +use crate::rpc::core::CoreRPCLike; + +impl Platform +where + C: CoreRPCLike, +{ + /// Runs a block proposal, either from process proposal or prepare proposal. + /// + /// This function takes a `BlockProposal` and a `Transaction` as input and processes the block + /// proposal. It first validates the block proposal and then processes raw state transitions, + /// withdrawal transactions, and block fees. It also updates the validator set. + /// + /// # Arguments + /// + /// * `block_proposal` - The block proposal to be processed. + /// * `known_from_us` - Do we know that we made this block proposal?. + /// * `transaction` - The transaction associated with the block proposal. + /// + /// # Returns + /// + /// * `Result, Error>` - If the block proposal is + /// successfully processed, it returns a `ValidationResult` containing the `BlockExecutionOutcome`. + /// If the block proposal processing fails, it returns an `Error`. Consensus errors are returned + /// in the `ValidationResult`, while critical system errors are returned in the `Result`. + /// + /// # Errors + /// + /// This function may return an `Error` variant if there is a problem with processing the block + /// proposal, updating the core info, processing raw state transitions, or processing block fees. + /// + pub(super) fn run_block_proposal_v1( + &self, + block_proposal: block_proposal::v0::BlockProposal, + known_from_us: bool, + epoch_info: EpochInfo, + transaction: &Transaction, + last_committed_platform_state: &PlatformState, + mut block_platform_state: PlatformState, + platform_version: &'static PlatformVersion, + timer: Option<&HistogramTiming>, + ) -> Result, Error> + { + tracing::trace!( + method = "run_block_proposal_v1", + ?block_proposal, + ?epoch_info, + "Running a block proposal for height: {}, round: {}", + block_proposal.height, + block_proposal.round, + ); + + // Run block proposal determines version by itself based on the previous + // state and block time. + // It should provide correct version on prepare proposal to block header + // and validate it on process proposal. + // If version set to 0 (default number value) it means we are on prepare proposal, + // so there is no need for validation. + if !known_from_us + && block_proposal.consensus_versions.app != platform_version.protocol_version as u64 + { + return Ok(ValidationResult::new_with_error( + AbciError::BadRequest(format!( + "received a block proposal with protocol version {}, expected: {}", + block_proposal.consensus_versions.app, platform_version.protocol_version + )) + .into(), + )); + } + + let last_block_time_ms = last_committed_platform_state.last_committed_block_time_ms(); + let last_block_height = last_committed_platform_state.last_committed_known_block_height_or( + self.config.abci.genesis_height.saturating_sub(1), + ); + let last_block_core_height = last_committed_platform_state + .last_committed_known_core_height_or(self.config.abci.genesis_core_height); + + // Init block execution context + let block_state_info = block_state_info::v0::BlockStateInfoV0::from_block_proposal( + &block_proposal, + last_block_time_ms, + ); + + // First let's check that this is the follower to a previous block + if !block_state_info.next_block_to(last_block_height, last_block_core_height)? { + // we are on the wrong height or round + return Ok(ValidationResult::new_with_error(AbciError::WrongBlockReceived(format!( + "received a block proposal for height: {} core height: {}, current height: {} core height: {}", + block_state_info.height, block_state_info.core_chain_locked_height, last_block_height, last_block_core_height + )).into())); + } + + // Cleanup block cache before we execute a new proposal + self.clear_drive_block_cache(platform_version)?; + + // destructure the block proposal + let block_proposal::v0::BlockProposal { + core_chain_locked_height, + core_chain_lock_update, + proposed_app_version, + proposer_pro_tx_hash, + validator_set_quorum_hash, + raw_state_transitions, + .. + } = block_proposal; + + let block_info = block_state_info.to_block_info( + Epoch::new(epoch_info.current_epoch_index()) + .expect("current epoch index should be in range"), + ); + + if epoch_info.is_epoch_change_but_not_genesis() { + tracing::info!( + epoch_index = epoch_info.current_epoch_index(), + "epoch change occurring from epoch {} to epoch {}", + epoch_info + .previous_epoch_index() + .expect("must be set since we aren't on genesis"), + epoch_info.current_epoch_index(), + ); + } + + // Update block platform state with current and next epoch protocol versions + // if it was proposed + // This is happening only on epoch change + self.upgrade_protocol_version_on_epoch_change( + &block_info, + &epoch_info, + last_committed_platform_state, + &mut block_platform_state, + transaction, + platform_version, + )?; + + // If there is a core chain lock update, we should start by verifying it + if let Some(core_chain_lock_update) = core_chain_lock_update.as_ref() { + if !known_from_us { + let verification_result = self.verify_chain_lock( + block_state_info.round, // the round is to allow us to bypass local verification in case of chain stall + &block_platform_state, + core_chain_lock_update, + true, // if it's not known from us, then we should try submitting it + platform_version, + ); + + let VerifyChainLockResult { + chain_lock_signature_is_deserializable, + found_valid_locally, + found_valid_by_core, + core_is_synced, + } = match verification_result { + Ok(verification_result) => verification_result, + Err(Error::Execution(e)) => { + // This will happen only if an internal version error + return Err(Error::Execution(e)); + } + Err(e) => { + // This will happen only if a core rpc error + return Ok(ValidationResult::new_with_error( + AbciError::InvalidChainLock(e.to_string()).into(), + )); + } + }; + + if !chain_lock_signature_is_deserializable { + return Ok(ValidationResult::new_with_error( + AbciError::InvalidChainLock(format!( + "received a chain lock for height {} that has a signature that can not be deserialized {:?}", + block_info.height, core_chain_lock_update, + )) + .into(), + )); + } + + if let Some(found_valid_locally) = found_valid_locally { + // This means we are able to check if the chain lock is valid + if !found_valid_locally { + // The signature was not valid + return Ok(ValidationResult::new_with_error( + AbciError::InvalidChainLock(format!( + "received a chain lock for height {} that we figured out was invalid based on platform state {:?}", + block_info.height, core_chain_lock_update, + )) + .into(), + )); + } + } + + if let Some(found_valid_by_core) = found_valid_by_core { + // This means we asked core if the chain lock was valid + if !found_valid_by_core { + // Core said it wasn't valid + return Ok(ValidationResult::new_with_error( + AbciError::InvalidChainLock(format!( + "received a chain lock for height {} that is invalid based on a core request {:?}", + block_info.height, core_chain_lock_update, + )) + .into(), + )); + } + } + + if let Some(core_is_synced) = core_is_synced { + // Core is just not synced + if !core_is_synced { + // The submission was not accepted by core + return Ok(ValidationResult::new_with_error( + AbciError::ChainLockedBlockNotKnownByCore(format!( + "received a chain lock for height {} that we could not accept because core is not synced {:?}", + block_info.height, core_chain_lock_update, + )) + .into(), + )); + } + } + } + } + + // Update the masternode list and create masternode identities and also update the active quorums + self.update_core_info( + Some(last_committed_platform_state), + &mut block_platform_state, + core_chain_locked_height, + false, + &block_info, + transaction, + platform_version, + )?; + + // Update the validator proposed app version + // It should be called after protocol version upgrade + self.drive + .update_validator_proposed_app_version( + proposer_pro_tx_hash, + proposed_app_version as u32, + Some(transaction), + &platform_version.drive, + ) + .map_err(|e| { + Error::Execution(ExecutionError::UpdateValidatorProposedAppVersionError(e)) + })?; // This is a system error + + // Rebroadcast expired withdrawals if they exist + // We do that before we mark withdrawals as expired + // to rebroadcast them on the next block but not the same + // one + // TODO: It must be also only on core height change + self.rebroadcast_expired_withdrawal_documents( + &block_info, + last_committed_platform_state, + transaction, + platform_version, + )?; + + // Mark all previously broadcasted and chainlocked withdrawals as complete + // only when we are on a new core height + if block_state_info.core_chain_locked_height() != last_block_core_height { + self.update_broadcasted_withdrawal_statuses( + &block_info, + transaction, + platform_version, + )?; + } + + // Preparing withdrawal transactions for signing and broadcasting + // To process withdrawals we need to dequeue untiled transactions from the withdrawal transactions queue + // Untiled transactions then converted to unsigned transactions, appending current block information + // required for signature verification (core height and quorum hash) + // Then we save unsigned transaction bytes to block execution context + // to be signed (on extend_vote), verified (on verify_vote) and broadcasted (on finalize_block) + // Also, the dequeued untiled transaction added to the broadcasted transaction queue to for further + // resigning in case of failures. + let unsigned_withdrawal_transaction_bytes = self + .dequeue_and_build_unsigned_withdrawal_transactions( + validator_set_quorum_hash, + &block_info, + Some(transaction), + platform_version, + )?; + + // Run all dao platform events, such as vote tallying and distribution of contested documents + // This must be done before state transition processing + // Otherwise we would expect a proof after a successful vote that has since been cleaned up. + self.run_dao_platform_events( + &block_info, + last_committed_platform_state, + &block_platform_state, + Some(transaction), + platform_version, + )?; + + // Process transactions + let state_transitions_result = self.process_raw_state_transitions( + raw_state_transitions, + &block_platform_state, + &block_info, + transaction, + platform_version, + known_from_us, + timer, + )?; + + // Pool withdrawals into transactions queue + + // Takes queued withdrawals, creates untiled withdrawal transaction payload, saves them to queue + // Corresponding withdrawal documents are changed from queued to pooled + self.pool_withdrawals_into_transactions_queue( + &block_info, + last_committed_platform_state, + Some(transaction), + platform_version, + )?; + + // Cleans up the expired locks for withdrawal amounts + // to update daily withdrawal limit + // This is for example when we make a withdrawal for 30 Dash + // But we can only withdraw 1000 Dash a day + // after the withdrawal we should only be able to withdraw 970 Dash + // But 24 hours later that locked 30 comes back + self.clean_up_expired_locks_of_withdrawal_amounts( + &block_info, + transaction, + platform_version, + )?; + + // Create a new block execution context + + let mut block_execution_context: BlockExecutionContext = + block_execution_context::v0::BlockExecutionContextV0 { + block_state_info: block_state_info.clone().into(), + epoch_info, + unsigned_withdrawal_transactions: unsigned_withdrawal_transaction_bytes, + block_platform_state, + proposer_results: None, + } + .into(); + + // while we have the state transitions executed, we now need to process the block fees + let block_fees_v0: BlockFeesV0 = state_transitions_result.aggregated_fees().clone().into(); + + // Process fees + let processed_block_fees = self.process_block_fees_and_validate_sum_trees( + &block_execution_context, + block_fees_v0.into(), + transaction, + platform_version, + )?; + + tracing::debug!(block_fees = ?processed_block_fees, "block fees are processed"); + + let validator_set_update = self.validator_set_update( + block_proposal.proposer_pro_tx_hash, + last_committed_platform_state, + &mut block_execution_context, + platform_version, + )?; + + // HERE + let extended_block_info = ExtendedBlockInfoV0 { + basic_info: block_info, + app_hash: Default::default(), // will be set on restore + quorum_hash: block_proposal.validator_set_quorum_hash, + proposer_pro_tx_hash: block_proposal.proposer_pro_tx_hash, + signature: [0u8; 96], // we don't have it here, hope it's not needed + round: block_proposal.round, + block_id_hash: Default::default(), // we don't have it here, hope it's not needed + } + .into(); + // Saving info required to reconstruct platform state + let snapshot_state = block_execution_context + .block_platform_state() + .to_snapshot_state(extended_block_info, core_chain_locked_height)?; + self.store_reduced_platform_state(&snapshot_state, Some(transaction), platform_version)?; + + let root_hash = self + .drive + .grove + .root_hash(Some(transaction), &platform_version.drive.grove_version) + .unwrap() + .map_err(|e| Error::Drive(GroveDB(e)))?; //GroveDb errors are system errors + + block_execution_context + .block_state_info_mut() + .set_app_hash(Some(root_hash)); + + if tracing::enabled!(tracing::Level::TRACE) { + tracing::trace!( + method = "run_block_proposal_v0", + app_hash = hex::encode(root_hash), + platform_state_fingerprint = hex::encode( + block_execution_context + .block_platform_state() + .fingerprint()? + ), + "Block proposal executed successfully", + ); + } + + Ok(ValidationResult::new_with_data( + block_execution_outcome::v0::BlockExecutionOutcome { + app_hash: root_hash, + state_transitions_result, + validator_set_update, + platform_version, + block_execution_context, + }, + )) + } +} diff --git a/packages/rs-drive-abci/src/execution/mod.rs b/packages/rs-drive-abci/src/execution/mod.rs index 0e4b73c3f00..c3b315725d8 100644 --- a/packages/rs-drive-abci/src/execution/mod.rs +++ b/packages/rs-drive-abci/src/execution/mod.rs @@ -3,7 +3,7 @@ mod check_tx; /// Engine module pub mod engine; /// platform execution events -pub(in crate::execution) mod platform_events; +pub(crate) mod platform_events; /// Storage implementation for the execution state pub mod storage; /// Types needed in execution diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/mod.rs index f0a8e18930a..3251e226209 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/mod.rs @@ -1,4 +1,4 @@ mod update_core_info; mod update_masternode_identities; mod update_masternode_list; -mod update_quorum_info; +pub(crate) mod update_quorum_info; diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_core_info/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_core_info/mod.rs index 1196d4ebe92..ea7aafc1eb0 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_core_info/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_core_info/mod.rs @@ -25,7 +25,7 @@ where /// * block_platform_state - A mutable reference to the current platform state in the block /// execution context to be updated. /// * core_block_height - The current block height in the Dash Core. - /// * is_init_chain - A boolean indicating if the chain is being initialized. + /// * start_from_scratch - A boolean indicating if we should start from scratch (eg. the chain is being initialized). /// * block_info - A reference to the block information. /// * transaction - The current groveDB transaction. /// @@ -39,7 +39,7 @@ where platform_state: Option<&PlatformState>, block_platform_state: &mut PlatformState, core_block_height: u32, - is_init_chain: bool, + start_from_scratch: bool, block_info: &BlockInfo, transaction: &Transaction, platform_version: &PlatformVersion, @@ -54,7 +54,7 @@ where platform_state, block_platform_state, core_block_height, - is_init_chain, + start_from_scratch, block_info, transaction, platform_version, diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_core_info/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_core_info/v0/mod.rs index eb825d9ca8a..22fb3496ce1 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_core_info/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_core_info/v0/mod.rs @@ -23,7 +23,7 @@ where /// * block_platform_state - A mutable reference to the current platform state in the block /// execution context to be updated. /// * core_block_height - The current block height in the Dash Core. - /// * is_init_chain - A boolean indicating if the chain is being initialized. + /// * start_from_scratch - A boolean indicating if the chain is being initialized. /// * block_info - A reference to the block information. /// * transaction - The current groveDB transaction. /// @@ -38,13 +38,14 @@ where platform_state: Option<&PlatformState>, block_platform_state: &mut PlatformState, core_block_height: u32, - is_init_chain: bool, + start_from_scratch: bool, block_info: &BlockInfo, transaction: &Transaction, platform_version: &PlatformVersion, ) -> Result<(), Error> { // the core height of the block platform state is the last committed - if !is_init_chain && block_platform_state.last_committed_core_height() == core_block_height + if !start_from_scratch + && block_platform_state.last_committed_core_height() == core_block_height { // if we get the same height that we know we do not need to update core info return Ok(()); @@ -53,7 +54,7 @@ where platform_state, block_platform_state, core_block_height, - is_init_chain, + start_from_scratch, block_info, transaction, platform_version, @@ -63,7 +64,7 @@ where platform_state, block_platform_state, core_block_height, - false, + start_from_scratch, // TODO: ask if it was `false` by purpose platform_version, ) } diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs index f0de44e4709..b78400c8948 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/mod.rs @@ -40,7 +40,7 @@ where platform_state: Option<&PlatformState>, block_platform_state: &mut PlatformState, core_block_height: u32, - is_init_chain: bool, + start_from_scratch: bool, block_info: &BlockInfo, transaction: &Transaction, platform_version: &PlatformVersion, @@ -55,7 +55,7 @@ where platform_state, block_platform_state, core_block_height, - is_init_chain, + start_from_scratch, block_info, transaction, platform_version, diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/v0/mod.rs index 568a91b0b0b..b24590b69b4 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/v0/mod.rs @@ -36,7 +36,7 @@ where platform_state: Option<&PlatformState>, block_platform_state: &mut PlatformState, core_block_height: u32, - is_init_chain: bool, + start_from_scratch: bool, block_info: &BlockInfo, transaction: &Transaction, platform_version: &PlatformVersion, @@ -44,7 +44,9 @@ where if let Some(last_committed_block_info) = block_platform_state.last_committed_block_info().as_ref() { - if core_block_height == last_committed_block_info.basic_info().core_height { + if !start_from_scratch + && core_block_height == last_committed_block_info.basic_info().core_height + { tracing::debug!( method = "update_masternode_list_v0", "no update mnl at height {}", @@ -66,7 +68,7 @@ where } = self.update_state_masternode_list_v0( block_platform_state, core_block_height, - is_init_chain, + start_from_scratch, )?; self.update_masternode_identities( diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/mod.rs index 87510c71171..ff567593874 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/mod.rs @@ -1,4 +1,4 @@ -mod v0; +pub(crate) mod v0; use crate::error::execution::ExecutionError; use crate::error::Error; diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs index 23c9238b796..78ba26489b4 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs @@ -21,13 +21,13 @@ use dpp::dashcore::QuorumHash; use tracing::Level; #[derive(Copy, Clone)] -enum QuorumSetType { +pub enum QuorumSetType { ChainLock(QuorumType), InstantLock(QuorumType), } impl QuorumSetType { - fn quorum_type(&self) -> QuorumType { + pub(crate) fn quorum_type(&self) -> QuorumType { match self { QuorumSetType::ChainLock(quorum_type) => *quorum_type, QuorumSetType::InstantLock(quorum_type) => *quorum_type, diff --git a/packages/rs-drive-abci/src/execution/platform_events/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/mod.rs index 1ac0715b9d2..f6356773e02 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/mod.rs @@ -5,7 +5,7 @@ pub(in crate::execution) mod block_processing_end_events; /// Events happening what starting to process a block pub(in crate::execution) mod block_start; /// Update from core such as a masternode list update or quorums being updated -pub(in crate::execution) mod core_based_updates; +pub(crate) mod core_based_updates; /// Verify the chain lock pub(in crate::execution) mod core_chain_lock; /// Instant lock methods diff --git a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs index 03df8b08887..ed55bb85c50 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs @@ -21,7 +21,10 @@ use drive::drive::identity::withdrawals::paths::{ get_withdrawal_root_path, WITHDRAWAL_TRANSACTIONS_BROADCASTED_KEY, WITHDRAWAL_TRANSACTIONS_SUM_AMOUNT_TREE_KEY, }; -use drive::drive::prefunded_specialized_balances::prefunded_specialized_balances_for_voting_path_vec; +use drive::drive::prefunded_specialized_balances::{ + prefunded_specialized_balances_for_voting_path, + prefunded_specialized_balances_for_voting_path_vec, +}; use drive::drive::system::misc_path; use drive::drive::tokens::paths::{ token_distributions_root_path, token_timed_distributions_path, tokens_root_path, @@ -100,125 +103,6 @@ impl Platform { Ok(()) } - /// Initializes an empty sum tree for withdrawal transactions required for protocol version 4. - /// - /// This function is called during the transition to protocol version 4 to set up - /// an empty sum tree at the specified path if it does not already exist. - /// - /// # Parameters - /// - /// * `transaction`: A reference to the transaction context in which the changes should be applied. - /// * `platform_version`: The current platform version containing the updated protocol version and relevant configuration details. - /// - /// # Returns - /// - /// * `Ok(())`: If the transition to version 4 was successful. - /// * `Err(Error)`: If there was an issue creating or updating the necessary data structures. - fn transition_to_version_4( - &self, - platform_state: &PlatformState, - block_info: &BlockInfo, - transaction: &Transaction, - platform_version: &PlatformVersion, - ) -> Result<(), Error> { - // We are adding the withdrawal transactions sum amount tree - let path = get_withdrawal_root_path(); - self.drive.grove_insert_if_not_exists( - (&path).into(), - &WITHDRAWAL_TRANSACTIONS_SUM_AMOUNT_TREE_KEY, - Element::empty_sum_tree(), - Some(transaction), - None, - &platform_version.drive, - )?; - // We are adding a tree to store broadcasted transactions that might expire - self.drive.grove_insert_if_not_exists( - (&path).into(), - &WITHDRAWAL_TRANSACTIONS_BROADCASTED_KEY, - Element::empty_tree(), - Some(transaction), - None, - &platform_version.drive, - )?; - // We need to add all masternode owner keys - // This is because owner identities only had a withdrawal key - // But no owner key - for masternode in platform_state.full_masternode_list().values() { - let masternode_id = masternode.pro_tx_hash.to_byte_array(); - let key_request = IdentityKeysRequest { - identity_id: masternode_id, - request_type: KeyRequestType::AllKeys, - limit: None, - offset: None, - }; - - let old_owner_identity_keys = self - .drive - .fetch_identity_keys::( - key_request, - Some(transaction), - platform_version, - )?; - - if old_owner_identity_keys.is_empty() { - continue; - } - - let last_key_id = *old_owner_identity_keys - .keys() - .max() - .expect("there must be keys, we already checked"); - - let new_owner_key = Self::get_owner_identity_owner_key( - masternode.state.owner_address, - last_key_id + 1, - platform_version, - )?; - - tracing::trace!( - identity_id = ?masternode_id, - withdrawal_key = ?new_owner_key, - method = "transition_to_version_4", - "add new owner key to owner identity" - ); - - self.drive.add_new_non_unique_keys_to_identity( - masternode_id, - vec![new_owner_key], - block_info, - true, - Some(transaction), - platform_version, - )?; - } - Ok(()) - } - - /// Initializes the wallet contract that supports mobile wallets with additional - /// functionality - /// - /// This function is called during the transition from protocol version 5 to protocol version 6 - /// and higher to set up the wallet contract in the platform. - fn transition_to_version_6( - &self, - block_info: &BlockInfo, - transaction: &Transaction, - platform_version: &PlatformVersion, - ) -> Result<(), Error> { - let contract = - load_system_data_contract(SystemDataContract::WalletUtils, platform_version)?; - - self.drive.insert_contract( - &contract, - *block_info, - true, - Some(transaction), - platform_version, - )?; - - Ok(()) - } - /// When transitioning to version 8 we need to empty some specialized balances fn transition_to_version_8( &self, @@ -344,6 +228,125 @@ impl Platform { Ok(()) } + /// Initializes an empty sum tree for withdrawal transactions required for protocol version 4. + /// + /// This function is called during the transition to protocol version 4 to set up + /// an empty sum tree at the specified path if it does not already exist. + /// + /// # Parameters + /// + /// * `transaction`: A reference to the transaction context in which the changes should be applied. + /// * `platform_version`: The current platform version containing the updated protocol version and relevant configuration details. + /// + /// # Returns + /// + /// * `Ok(())`: If the transition to version 4 was successful. + /// * `Err(Error)`: If there was an issue creating or updating the necessary data structures. + fn transition_to_version_4( + &self, + platform_state: &PlatformState, + block_info: &BlockInfo, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + // We are adding the withdrawal transactions sum amount tree + let path = get_withdrawal_root_path(); + self.drive.grove_insert_if_not_exists( + (&path).into(), + &WITHDRAWAL_TRANSACTIONS_SUM_AMOUNT_TREE_KEY, + Element::empty_sum_tree(), + Some(transaction), + None, + &platform_version.drive, + )?; + // We are adding a tree to store broadcasted transactions that might expire + self.drive.grove_insert_if_not_exists( + (&path).into(), + &WITHDRAWAL_TRANSACTIONS_BROADCASTED_KEY, + Element::empty_tree(), + Some(transaction), + None, + &platform_version.drive, + )?; + // We need to add all masternode owner keys + // This is because owner identities only had a withdrawal key + // But no owner key + for masternode in platform_state.full_masternode_list().values() { + let masternode_id = masternode.pro_tx_hash.to_byte_array(); + let key_request = IdentityKeysRequest { + identity_id: masternode_id, + request_type: KeyRequestType::AllKeys, + limit: None, + offset: None, + }; + + let old_owner_identity_keys = self + .drive + .fetch_identity_keys::( + key_request, + Some(transaction), + platform_version, + )?; + + if old_owner_identity_keys.is_empty() { + continue; + } + + let last_key_id = *old_owner_identity_keys + .keys() + .max() + .expect("there must be keys, we already checked"); + + let new_owner_key = Self::get_owner_identity_owner_key( + masternode.state.owner_address, + last_key_id + 1, + platform_version, + )?; + + tracing::trace!( + identity_id = ?masternode_id, + withdrawal_key = ?new_owner_key, + method = "transition_to_version_4", + "add new owner key to owner identity" + ); + + self.drive.add_new_non_unique_keys_to_identity( + masternode_id, + vec![new_owner_key], + block_info, + true, + Some(transaction), + platform_version, + )?; + } + Ok(()) + } + + /// Initializes the wallet contract that supports mobile wallets with additional + /// functionality + /// + /// This function is called during the transition from protocol version 5 to protocol version 6 + /// and higher to set up the wallet contract in the platform. + fn transition_to_version_6( + &self, + block_info: &BlockInfo, + transaction: &Transaction, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + let contract = + load_system_data_contract(SystemDataContract::WalletUtils, platform_version)?; + + self.drive.insert_contract( + &contract, + *block_info, + true, + Some(transaction), + platform_version, + )?; + + Ok(()) + } + /// Adds all trees needed for tokens, also adds the token history system data contract /// /// This function is called during the transition from protocol version 5 to protocol version 6 diff --git a/packages/rs-drive-abci/src/execution/storage/fetch_reduced_platform_state/mod.rs b/packages/rs-drive-abci/src/execution/storage/fetch_reduced_platform_state/mod.rs new file mode 100644 index 00000000000..34f51a94700 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/storage/fetch_reduced_platform_state/mod.rs @@ -0,0 +1,34 @@ +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use dpp::reduced_platform_state::ReducedPlatformStateForSaving; +use dpp::version::PlatformVersion; +use drive::drive::Drive; +use drive::query::TransactionArg; + +mod v0; + +impl Platform { + /// Fetches execution state from grovedb storage + pub fn fetch_reduced_platform_state( + drive: &Drive, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + match platform_version + .drive_abci + .methods + .platform_reduced_state_storage + .fetch_reduced_platform_state + { + 0 => { + Platform::::fetch_reduced_platform_state_v0(drive, transaction, platform_version) + } + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "fetch_reduced_platform_state".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/storage/fetch_reduced_platform_state/v0/mod.rs b/packages/rs-drive-abci/src/execution/storage/fetch_reduced_platform_state/v0/mod.rs new file mode 100644 index 00000000000..9b400a4b602 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/storage/fetch_reduced_platform_state/v0/mod.rs @@ -0,0 +1,38 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use dpp::reduced_platform_state::ReducedPlatformStateForSaving; +use dpp::serialization::PlatformDeserializableFromVersionedStructure; +use dpp::version::PlatformVersion; +use drive::drive::Drive; +use drive::query::TransactionArg; + +impl Platform { + pub(super) fn fetch_reduced_platform_state_v0( + drive: &Drive, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result, Error> { + drive + .fetch_reduced_platform_state_bytes(transaction, platform_version) + .map_err(Error::Drive)? + .map(|bytes| { + ReducedPlatformStateForSaving::versioned_deserialize(&bytes, platform_version) + .inspect(|d| { + tracing::trace!( + len = bytes.len(), + reduced_platform_state = ?d, + "state_sync: reduced platform state deserialized successfully for version {}", + platform_version.protocol_version + ); + }) + .inspect_err(|e| + tracing::error!( + bytes = hex::encode(&bytes), + "Unable deserialize reduced platform state for version {}: {:?}", + platform_version.protocol_version,e + )).map_err(Error::Protocol) + + }) + .transpose() + } +} diff --git a/packages/rs-drive-abci/src/execution/storage/mod.rs b/packages/rs-drive-abci/src/execution/storage/mod.rs index 54302920e5d..b452ea11d5f 100644 --- a/packages/rs-drive-abci/src/execution/storage/mod.rs +++ b/packages/rs-drive-abci/src/execution/storage/mod.rs @@ -1,2 +1,4 @@ mod fetch_platform_state; +mod fetch_reduced_platform_state; mod store_platform_state; +mod store_reduced_platform_state; diff --git a/packages/rs-drive-abci/src/execution/storage/store_reduced_platform_state/mod.rs b/packages/rs-drive-abci/src/execution/storage/store_reduced_platform_state/mod.rs new file mode 100644 index 00000000000..8b5ba1b647d --- /dev/null +++ b/packages/rs-drive-abci/src/execution/storage/store_reduced_platform_state/mod.rs @@ -0,0 +1,33 @@ +mod v0; + +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::platform_types::platform::Platform; +use crate::platform_types::platform_state::PlatformState; +use dpp::reduced_platform_state::ReducedPlatformStateForSaving; +use dpp::version::PlatformVersion; +use drive::query::TransactionArg; + +impl Platform { + /// Store the execution state in grovedb storage + pub fn store_reduced_platform_state( + &self, + state: &ReducedPlatformStateForSaving, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version + .drive_abci + .methods + .platform_state_storage + .store_platform_state + { + 0 => self.store_reduced_platform_state_v0(state, transaction, platform_version), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "store_reduced_platform_state".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/storage/store_reduced_platform_state/v0/mod.rs b/packages/rs-drive-abci/src/execution/storage/store_reduced_platform_state/v0/mod.rs new file mode 100644 index 00000000000..e015ae3e4ee --- /dev/null +++ b/packages/rs-drive-abci/src/execution/storage/store_reduced_platform_state/v0/mod.rs @@ -0,0 +1,30 @@ +use crate::error::Error; +use crate::platform_types::platform::Platform; +use dpp::reduced_platform_state::ReducedPlatformStateForSaving; +use dpp::serialization::PlatformSerializable; +use dpp::version::PlatformVersion; +use drive::query::TransactionArg; + +impl Platform { + pub(super) fn store_reduced_platform_state_v0( + &self, + state: &ReducedPlatformStateForSaving, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + // TODO: refactor to platform serialization + + let state_bytes = state.serialize_to_bytes()?; + + tracing::trace!( + reduced_state=?state, + len = state_bytes.len(), + "state_sync: storing reduced platform state" + ); + + self.drive + .store_reduced_platform_state_bytes(&state_bytes, transaction, platform_version) + .map_err(Error::Drive)?; + Ok(()) + } +} diff --git a/packages/rs-drive-abci/src/logging/level.rs b/packages/rs-drive-abci/src/logging/level.rs index 0b89ac56ddd..65ec7288c5c 100644 --- a/packages/rs-drive-abci/src/logging/level.rs +++ b/packages/rs-drive-abci/src/logging/level.rs @@ -114,7 +114,7 @@ impl TryFrom<&LogLevel> for EnvFilter { ) .expect("should be a valid log specification"), LogLevel::Trace => EnvFilter::try_new( - "debug,tenderdash_abci=trace,drive_abci=trace,drive=trace,drive_grovedb_operations=off,dpp=trace", + "debug,tenderdash_abci=trace,drive_abci=trace,drive=trace,drive_grovedb_operations=off,dpp=trace,h2::codec=info", ) .expect("should be a valid log specification"), LogLevel::Paranoid => { diff --git a/packages/rs-drive-abci/src/platform_types/mod.rs b/packages/rs-drive-abci/src/platform_types/mod.rs index b973b9051eb..92ae30b58c2 100644 --- a/packages/rs-drive-abci/src/platform_types/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/mod.rs @@ -31,3 +31,6 @@ pub mod validator_set; pub mod verify_chain_lock_result; /// Withdrawal types pub mod withdrawal; + +/// Snapshots +pub mod snapshot; diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs index d2c89b7f5e2..7185560eed6 100644 --- a/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs @@ -27,6 +27,7 @@ use crate::platform_types::signature_verification_quorum_set::SignatureVerificat use dashcore_rpc::json::MasternodeListItem; use dpp::block::block_info::BlockInfo; use dpp::fee::default_costs::CachedEpochIndexFeeVersions; +use dpp::reduced_platform_state::ReducedPlatformStateForSaving; use dpp::util::hash::hash_double; use std::collections::BTreeMap; @@ -64,6 +65,21 @@ impl PlatformSerializable for PlatformState { } } +impl PlatformState { + /// Generate state in a form that is saved for snapshot recovery purposes + pub fn to_snapshot_state( + &self, + current_block_info: ExtendedBlockInfo, + proposed_core_chain_locked_height: u32, + ) -> Result { + match self { + PlatformState::V0(v0) => { + v0.to_snapshot_state(current_block_info, proposed_core_chain_locked_height) + } + } + } +} + impl PlatformDeserializableFromVersionedStructure for PlatformState { fn versioned_deserialize( data: &[u8], diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs index cf8ea67b8c9..401f67fe690 100644 --- a/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs @@ -1,5 +1,6 @@ mod old_structures; +use crate::abci::AbciError; use crate::error::execution::ExecutionError; use crate::error::Error; use dashcore_rpc::dashcore_rpc_json::MasternodeListItem; @@ -12,13 +13,14 @@ use dpp::dashcore::hashes::Hash; use dpp::platform_value::Bytes32; +use dpp::reduced_platform_state::ReducedPlatformStateForSaving; use drive::dpp::util::deserializer::ProtocolVersion; use indexmap::IndexMap; use crate::platform_types::masternode::Masternode; use crate::platform_types::validator_set::ValidatorSet; use dpp::block::block_info::{BlockInfo, DEFAULT_BLOCK_INFO}; -use dpp::block::extended_block_info::v0::ExtendedBlockInfoV0Getters; +use dpp::block::extended_block_info::v0::{ExtendedBlockInfoV0, ExtendedBlockInfoV0Getters}; use dpp::version::{PlatformVersion, TryIntoPlatformVersioned}; use crate::config::PlatformConfig; @@ -30,6 +32,7 @@ use dpp::fee::default_costs::{ CachedEpochIndexFeeVersions, CachedEpochIndexFeeVersionsFieldsBeforeVersion4, EpochIndexFeeVersionsForStorage, }; +use dpp::reduced_platform_state::v0::ReducedPlatformStateForSavingV0; use dpp::version::fee::FeeVersion; use itertools::Itertools; use std::collections::BTreeMap; @@ -114,6 +117,7 @@ impl Debug for PlatformStateV0 { "instant_lock_validating_quorums", &self.instant_lock_validating_quorums, ) + .field("previous_fee_versions", &self.previous_fee_versions) .finish() } } @@ -252,6 +256,70 @@ impl TryFrom for PlatformStateForSavingV1 { } } +impl PlatformStateV0 { + /// Convert to a snapshot state + pub(super) fn to_snapshot_state( + &self, + current_block_info: ExtendedBlockInfo, + proposed_core_chain_locked_height: u32, + ) -> Result { + let quorums = self.validator_sets(); + let quorum_positions = quorums + .into_iter() + .map(|(block_hash, _)| (block_hash.to_byte_array().to_vec())) + .collect(); + + let last_block_info: Option = self + .last_committed_block_info() + .clone() + .map(|info| filter_extended_block_info(info.clone())); + // .ok_or(AbciError::StateSyncInternalError( + // "last_committed_block_info must be set before saving the state for state sync" + // .to_string(), + // ))?; + + Ok(ReducedPlatformStateForSaving::V0( + ReducedPlatformStateForSavingV0 { + current_protocol_version_in_consensus: self.current_protocol_version_in_consensus, + next_epoch_protocol_version: self.next_epoch_protocol_version, + current_validator_set_quorum_hash: self + .current_validator_set_quorum_hash + .to_byte_array() + .into(), + next_validator_set_quorum_hash: self + .next_validator_set_quorum_hash + .map(|quorum_hash| quorum_hash.to_byte_array().into()), + previous_fee_versions: self + .previous_fee_versions + .iter() + .map(|(&epoch_index, fee_version)| { + (epoch_index, fee_version.fee_version_number) + }) + .collect(), + quorum_positions, + last_committed_block_info: Some(filter_extended_block_info(current_block_info)), // we assume this is what we committed + proposed_core_chain_locked_height, + }, + )) + } +} + +/// Remove fields from [ExtendedBlockInfo] that cannot be saved to a snapshot state. +/// +/// Helper function to remove fields from [ExtendedBlockInfo] that cannot be saved to a snapshot state +/// because they are not always available (eg. on proposer) and can cause app hash mismatch. +fn filter_extended_block_info(input: ExtendedBlockInfo) -> ExtendedBlockInfo { + match input { + ExtendedBlockInfo::V0(v0) => ExtendedBlockInfoV0 { + app_hash: Default::default(), // will be set on restore + signature: [0u8; 96], // we don't have it here, hope it's not needed + block_id_hash: Default::default(), // we don't have it here, hope it's not needed + ..v0 + } + .into(), + } +} + impl From for PlatformStateV0 { fn from(value: PlatformStateForSavingV0) -> Self { PlatformStateV0 { diff --git a/packages/rs-drive-abci/src/platform_types/snapshot/mod.rs b/packages/rs-drive-abci/src/platform_types/snapshot/mod.rs new file mode 100644 index 00000000000..1d76fb44ac6 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/snapshot/mod.rs @@ -0,0 +1,229 @@ +use std::{ + fs, + path::{Path, PathBuf}, + pin::Pin, +}; + +use crate::error::Error; +use bincode::{config, Decode, Encode}; +use dapi_grpc::tonic; +use dpp::version::PlatformVersion; +use drive::error::drive::DriveError; +use drive::error::Error::{Drive, GroveDB}; +use drive::grovedb::replication::MultiStateSyncSession; +use drive::grovedb::GroveDb; +use prost::Message; +use tenderdash_abci::proto::abci; + +const SNAPSHOT_KEY: &[u8] = b"snapshots"; + +const CHUNK_SIZE_16MB: usize = 16 * 1024 * 1024; + +const SNAPSHOT_VERSION: u16 = 1; + +/// Snapshot entity +#[derive(Clone, Encode, Decode, PartialEq, Debug)] +pub struct Snapshot { + /// Block height + pub height: i64, + /// Version + pub version: u16, + /// Path to the checkpoint + pub path: String, + /// Root hash of the checkpoint + pub hash: [u8; 32], + /// Metadata + pub metadata: Vec, +} + +/// Snapshot manager is responsible for creating and managing snapshots to keep only the certain +/// number of snapshots and remove the old ones +#[derive(Default, Clone)] +pub struct SnapshotManager { + freq: i64, + number_stored_snapshots: usize, + checkpoints_path: PathBuf, +} + +/// Snapshot manager is responsible for creating and managing snapshots to keep only the certain +/// number of snapshots and remove the old ones +pub struct SnapshotFetchingSession<'db> { + /// Snapshot accepted + pub snapshot: abci::Snapshot, + /// Snapshot accepted + pub app_hash: Vec, + /// Snapshot accepted + pub state_sync_info: Pin>>, +} + +impl<'db> SnapshotFetchingSession<'db> { + /// Creates a new `SnapshotFetchingSession`. + /// + /// # Parameters + /// + /// - `snapshot`: The accepted snapshot. + /// - `app_hash`: The application hash associated with the snapshot. + /// - `state_sync_info`: The state sync information. + /// + /// # Returns + /// + /// A new instance of `SnapshotFetchingSession`. + pub fn new( + snapshot: abci::Snapshot, + app_hash: Vec, + state_sync_info: Pin>>, + ) -> Self { + SnapshotFetchingSession { + snapshot, + app_hash, + state_sync_info, + } + } +} + +impl SnapshotManager { + /// Create a new instance of snapshot manager + pub fn new(checkpoints_path: PathBuf, number_stored_snapshots: usize, freq: i64) -> Self { + if let Err(e) = fs::create_dir_all(checkpoints_path.clone()) { + tracing::error!( + "Failed to create directory {}: {}", + checkpoints_path.display(), + e + ); + } + Self { + freq, + number_stored_snapshots, + checkpoints_path, + } + } + + /// Return a persisted list of snapshots + pub fn get_snapshots(&self, grove: &GroveDb) -> Result, Error> { + let data = grove + .get_aux(SNAPSHOT_KEY, None) + .value + .map_err(|e| Error::Drive(GroveDB(e)))?; + + match data { + Some(data) => { + let conf = config::standard(); + let (mut decoded, _): (Vec, usize) = + bincode::decode_from_slice(data.as_slice(), conf) + .map_err(|e| Error::Drive(Drive(DriveError::Snapshot(e.to_string()))))?; + decoded.sort_by(|a, b| a.height.cmp(&b.height)); + Ok(decoded) + } + None => Ok(vec![]), + } + } + + /// Return the snapshot a requested height + pub fn get_snapshot_at_height( + &self, + grove: &GroveDb, + height: i64, + ) -> Result, Error> { + let snapshots = self.get_snapshots(&grove)?; + let matched_snapshot = snapshots + .iter() + .find(|&snapshot| snapshot.height == height) + .cloned(); + Ok(matched_snapshot) + } + + /// Create a new snapshot for the given height, if a height is not a multiple of N, + /// it will be skipped. + pub fn create_snapshot(&self, grove: &GroveDb, height: i64) -> Result<(), Error> { + if height == 0 || height % self.freq != 0 { + return Ok(()); + } + let checkpoints_path_base = self.checkpoints_path.clone(); + let checkpoint_path: PathBuf = checkpoints_path_base.join(height.to_string()); + grove + .create_checkpoint(&checkpoint_path) + .map_err(|e| Error::Drive(GroveDB(e)))?; + + let root_hash = grove + .root_hash(None, &PlatformVersion::latest().drive.grove_version) + .value + .map_err(|e| Error::Drive(Drive(DriveError::Snapshot(e.to_string()))))?; + + let snapshot = Snapshot { + height, + version: SNAPSHOT_VERSION, + path: checkpoint_path.to_string_lossy().into_owned(), + hash: root_hash as [u8; 32], + metadata: vec![], + }; + + let mut snapshots = self.get_snapshots(grove)?; + snapshots.push(snapshot); + snapshots = self.prune_excess_snapshots(snapshots)?; + self.save_snapshots(grove, snapshots) + } + + fn prune_excess_snapshots(&self, snapshots: Vec) -> Result, Error> { + if snapshots.len() <= self.number_stored_snapshots { + return Ok(snapshots); + } + let separator = snapshots.len() - self.number_stored_snapshots; + for snapshot in &snapshots[0..separator] { + if Path::new(&snapshot.path).is_dir() { + fs::remove_dir_all(&snapshot.path) + .map_err(|e| Error::Drive(Drive(DriveError::Snapshot(e.to_string()))))?; + } + } + Ok(snapshots[separator..].to_vec()) + } + + fn save_snapshots(&self, grove: &GroveDb, snapshots: Vec) -> Result<(), Error> { + let conf = config::standard(); + let data: Vec = bincode::encode_to_vec(snapshots, conf) + .map_err(|e| Error::Drive(Drive(DriveError::Snapshot(e.to_string()))))?; + grove + .put_aux(SNAPSHOT_KEY, data.as_slice(), None, None) + .value + .map_err(|e| Error::Drive(GroveDB(e)))?; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::fs; + + #[test] + fn test_create_snapshot() { + let test_cases = vec![ + (1000, 1000, vec![1000]), + (1000, 1001, vec![1000, 1001]), + (1000, 1002, vec![1000, 1001, 1002]), + (1000, 1004, vec![1002, 1003, 1004]), + (1000, 1005, vec![1003, 1004, 1005]), + ]; + for (start, end, want) in test_cases { + let grove_dir = tempfile::tempdir().unwrap(); + let checkpoints_dir = tempfile::tempdir().unwrap(); + let grove = GroveDb::open(grove_dir.path()).unwrap(); + let manager = SnapshotManager::new( + checkpoints_dir.path().to_str().unwrap().to_string().into(), + 3, + 1, + ); + for height in start..=end { + manager.create_snapshot(&grove, height).unwrap(); + } + let snapshots = manager.get_snapshots(&grove).unwrap(); + let res: Vec = snapshots.iter().map(|s| s.height).collect(); + assert_eq!(want, res); + + let paths: Vec = snapshots.iter().map(|s| s.path.to_string()).collect(); + for path in paths { + assert!(Path::new(&path).exists()); + } + fs::remove_dir_all(grove_dir.path()).unwrap(); + } + } +} diff --git a/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs index 6b55d7532d3..10c4bb7eb35 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/voting_tests.rs @@ -1686,11 +1686,8 @@ mod tests { // All vote counts are weighted, so for evonodes, these are in multiples of 4 assert_eq!(first_contender.vote_count, Some(60)); - assert_eq!(second_contender.vote_count, Some(4)); - assert_eq!(lock_vote_tally, Some(4)); - assert_eq!(abstain_vote_tally, Some(8)); assert_eq!( diff --git a/packages/rs-drive-abci/tests/strategy_tests/withdrawal_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/withdrawal_tests.rs index 17484987093..f5748dc7b4e 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/withdrawal_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/withdrawal_tests.rs @@ -1618,7 +1618,7 @@ mod tests { assert_eq!( total_credits_balance.total_identity_balances, - 409997575280380 + 409997575236380 ); // Around 4100 Dash. assert_eq!( @@ -2334,7 +2334,7 @@ mod tests { assert_eq!( total_credits_balance.total_identity_balances, - 409997575280380 + 409997575236380 ); // Around 4100 Dash. assert_eq!( diff --git a/packages/rs-drive-proof-verifier/Cargo.toml b/packages/rs-drive-proof-verifier/Cargo.toml index 9af01f3cc48..bbf0528d584 100644 --- a/packages/rs-drive-proof-verifier/Cargo.toml +++ b/packages/rs-drive-proof-verifier/Cargo.toml @@ -37,6 +37,7 @@ platform-serialization-derive = { path = "../rs-platform-serialization-derive", platform-serialization = { path = "../rs-platform-serialization" } tenderdash-abci = { git = "https://github.com/dashpay/rs-tenderdash-abci", version = "1.4.0", tag = "v1.4.0", features = [ "crypto", + "serde", ], default-features = false } tracing = { version = "0.1.37" } serde = { version = "1.0.219", default-features = false, optional = true } diff --git a/packages/rs-drive/src/drive/platform_state/fetch_last_block_info_bytes/mod.rs b/packages/rs-drive/src/drive/platform_state/fetch_last_block_info_bytes/mod.rs new file mode 100644 index 00000000000..91d2c776a47 --- /dev/null +++ b/packages/rs-drive/src/drive/platform_state/fetch_last_block_info_bytes/mod.rs @@ -0,0 +1,30 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +mod v0; + +impl Drive { + /// Fetches last block info from grove (needed for Platform reconstruction once state sync is completed) + pub fn fetch_last_block_info_bytes( + &self, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .last_block_info + .fetch_last_block_info_bytes + { + 0 => self.fetch_last_block_info_bytes_v0(transaction, platform_version), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_last_block_info_bytes".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/platform_state/fetch_last_block_info_bytes/v0/mod.rs b/packages/rs-drive/src/drive/platform_state/fetch_last_block_info_bytes/v0/mod.rs new file mode 100644 index 00000000000..9cce25ecc5c --- /dev/null +++ b/packages/rs-drive/src/drive/platform_state/fetch_last_block_info_bytes/v0/mod.rs @@ -0,0 +1,38 @@ +use crate::drive::platform_state::LAST_BLOCK_INFO_KEY; +use crate::drive::system::misc_path_vec; +use crate::drive::Drive; +use crate::error::Error; +use grovedb::{PathQuery, Query, TransactionArg}; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn fetch_last_block_info_bytes_v0( + &self, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + let mut query = Query::new(); + query.insert_key(Vec::from(LAST_BLOCK_INFO_KEY)); + + let path_query = PathQuery::new_unsized(misc_path_vec(), query.clone()); + + let (res, _) = self + .grove + .query_item_value( + &path_query, + true, + false, + true, + transaction, + &platform_version.drive.grove_version, + ) + .value?; + + if res.len() != 1 { + return Err(Error::GroveDB(grovedb::Error::InvalidQuery( + "Invalid number of last block info elements", + ))); + } + Ok(res.into_iter().next()) + } +} diff --git a/packages/rs-drive/src/drive/platform_state/fetch_reduced_platform_state_bytes/mod.rs b/packages/rs-drive/src/drive/platform_state/fetch_reduced_platform_state_bytes/mod.rs new file mode 100644 index 00000000000..41d792cc7c3 --- /dev/null +++ b/packages/rs-drive/src/drive/platform_state/fetch_reduced_platform_state_bytes/mod.rs @@ -0,0 +1,30 @@ +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +mod v0; + +impl Drive { + /// Fetches execution state from grovedb storage + pub fn fetch_reduced_platform_state_bytes( + &self, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + match platform_version + .drive + .methods + .reduced_platform_state + .fetch_reduced_platform_state_bytes + { + 0 => self.fetch_reduced_platform_state_bytes_v0(transaction, platform_version), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "fetch_reduced_platform_state_bytes".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/platform_state/fetch_reduced_platform_state_bytes/v0/mod.rs b/packages/rs-drive/src/drive/platform_state/fetch_reduced_platform_state_bytes/v0/mod.rs new file mode 100644 index 00000000000..1a10f985b53 --- /dev/null +++ b/packages/rs-drive/src/drive/platform_state/fetch_reduced_platform_state_bytes/v0/mod.rs @@ -0,0 +1,38 @@ +use crate::drive::platform_state::REDUCED_PLATFORM_STATE_KEY; +use crate::drive::system::misc_path_vec; +use crate::drive::Drive; +use crate::error::Error; +use grovedb::{PathQuery, Query, TransactionArg}; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn fetch_reduced_platform_state_bytes_v0( + &self, + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result>, Error> { + let mut query = Query::new(); + query.insert_key(Vec::from(REDUCED_PLATFORM_STATE_KEY)); + + let path_query = PathQuery::new_unsized(misc_path_vec(), query.clone()); + + let (res, _) = self + .grove + .query_item_value( + &path_query, + true, + false, + true, + transaction, + &platform_version.drive.grove_version, + ) + .value?; + + if res.len() != 1 { + return Err(Error::GroveDB(grovedb::Error::InvalidQuery( + "Invalid number of reduced platform state elements", + ))); + } + Ok(res.into_iter().next()) + } +} diff --git a/packages/rs-drive/src/drive/platform_state/mod.rs b/packages/rs-drive/src/drive/platform_state/mod.rs index d6a0ce16c49..c1aebf20bc9 100644 --- a/packages/rs-drive/src/drive/platform_state/mod.rs +++ b/packages/rs-drive/src/drive/platform_state/mod.rs @@ -1,4 +1,10 @@ +mod fetch_last_block_info_bytes; mod fetch_platform_state_bytes; +mod fetch_reduced_platform_state_bytes; +mod store_last_block_info_bytes; mod store_platform_state_bytes; +mod store_reduced_platform_state_bytes; const PLATFORM_STATE_KEY: &[u8; 11] = b"saved_state"; +const REDUCED_PLATFORM_STATE_KEY: &[u8; 19] = b"reduced_saved_state"; +const LAST_BLOCK_INFO_KEY: &[u8; 15] = b"last_block_info"; diff --git a/packages/rs-drive/src/drive/platform_state/store_last_block_info_bytes/mod.rs b/packages/rs-drive/src/drive/platform_state/store_last_block_info_bytes/mod.rs new file mode 100644 index 00000000000..d0489a9c399 --- /dev/null +++ b/packages/rs-drive/src/drive/platform_state/store_last_block_info_bytes/mod.rs @@ -0,0 +1,35 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Store the execution state in grovedb storage + pub fn store_last_block_info_bytes( + &self, + last_block_info_bytes: &[u8], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version + .drive + .methods + .last_block_info + .store_last_block_info_bytes + { + 0 => self.store_last_block_info_bytes_v0( + last_block_info_bytes, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "store_last_block_info_bytes".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/platform_state/store_last_block_info_bytes/v0/mod.rs b/packages/rs-drive/src/drive/platform_state/store_last_block_info_bytes/v0/mod.rs new file mode 100644 index 00000000000..a794b343d99 --- /dev/null +++ b/packages/rs-drive/src/drive/platform_state/store_last_block_info_bytes/v0/mod.rs @@ -0,0 +1,29 @@ +use crate::drive::platform_state::LAST_BLOCK_INFO_KEY; +use crate::drive::system::misc_path; +use crate::drive::Drive; +use crate::error::Error; +use dpp::version::PlatformVersion; +use grovedb::operations::insert::InsertOptions; +use grovedb::{Element, TransactionArg}; + +impl Drive { + pub(super) fn store_last_block_info_bytes_v0( + &self, + last_block_info_bytes: &[u8], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + self.grove + .insert( + &misc_path(), + LAST_BLOCK_INFO_KEY, + Element::Item(last_block_info_bytes.to_vec(), None), + Some(InsertOptions::default()), + transaction, + &platform_version.drive.grove_version, + ) + .unwrap() + .map_err(Error::GroveDB)?; + Ok(()) + } +} diff --git a/packages/rs-drive/src/drive/platform_state/store_reduced_platform_state_bytes/mod.rs b/packages/rs-drive/src/drive/platform_state/store_reduced_platform_state_bytes/mod.rs new file mode 100644 index 00000000000..91807d10b3e --- /dev/null +++ b/packages/rs-drive/src/drive/platform_state/store_reduced_platform_state_bytes/mod.rs @@ -0,0 +1,35 @@ +mod v0; + +use crate::drive::Drive; +use crate::error::drive::DriveError; +use crate::error::Error; +use dpp::version::PlatformVersion; +use grovedb::TransactionArg; + +impl Drive { + /// Store the execution state in grovedb storage + pub fn store_reduced_platform_state_bytes( + &self, + state_bytes: &[u8], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + match platform_version + .drive + .methods + .reduced_platform_state + .store_reduced_platform_state_bytes + { + 0 => self.store_reduced_platform_state_bytes_v0( + state_bytes, + transaction, + platform_version, + ), + version => Err(Error::Drive(DriveError::UnknownVersionMismatch { + method: "store_reduced_platform_state_bytes".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive/src/drive/platform_state/store_reduced_platform_state_bytes/v0/mod.rs b/packages/rs-drive/src/drive/platform_state/store_reduced_platform_state_bytes/v0/mod.rs new file mode 100644 index 00000000000..d78322816e3 --- /dev/null +++ b/packages/rs-drive/src/drive/platform_state/store_reduced_platform_state_bytes/v0/mod.rs @@ -0,0 +1,29 @@ +use crate::drive::platform_state::REDUCED_PLATFORM_STATE_KEY; +use crate::drive::system::misc_path; +use crate::drive::Drive; +use crate::error::Error; +use grovedb::operations::insert::InsertOptions; +use grovedb::{Element, TransactionArg}; +use platform_version::version::PlatformVersion; + +impl Drive { + pub(super) fn store_reduced_platform_state_bytes_v0( + &self, + reduced_state_bytes: &[u8], + transaction: TransactionArg, + platform_version: &PlatformVersion, + ) -> Result<(), Error> { + self.grove + .insert( + &misc_path(), + REDUCED_PLATFORM_STATE_KEY, + Element::Item(reduced_state_bytes.to_vec(), None), + Some(InsertOptions::default()), + transaction, + &platform_version.drive.grove_version, + ) + .unwrap() + .map_err(Error::GroveDB)?; + Ok(()) + } +} diff --git a/packages/rs-drive/src/error/drive.rs b/packages/rs-drive/src/error/drive.rs index 2f318704837..24abd2aded2 100644 --- a/packages/rs-drive/src/error/drive.rs +++ b/packages/rs-drive/src/error/drive.rs @@ -190,6 +190,10 @@ pub enum DriveError { #[error("data contract not found: {0}")] DataContractNotFound(String), + /// Error todo + #[error("snapshot error")] + Snapshot(String), + /// Data Contract not found #[error("data contract does not have a start moment: {0}")] ContractDoesNotHaveAStartMoment(Identifier), diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/mod.rs index 18afbf4a153..ca4c0ed2df7 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/mod.rs @@ -26,6 +26,8 @@ pub struct DriveAbciMethodVersions { pub block_start: DriveAbciBlockStartMethodVersions, pub block_end: DriveAbciBlockEndMethodVersions, pub platform_state_storage: DriveAbciPlatformStateStorageMethodVersions, + pub platform_reduced_state_storage: DriveAbciReducedPlatformStateStorageMethodVersions, + pub last_block_info_storage: DriveAbciLastBlockInfoStorageMethodVersions, } #[derive(Clone, Debug, Default)] @@ -34,6 +36,18 @@ pub struct DriveAbciPlatformStateStorageMethodVersions { pub store_platform_state: FeatureVersion, } +#[derive(Clone, Debug, Default)] +pub struct DriveAbciReducedPlatformStateStorageMethodVersions { + pub fetch_reduced_platform_state: FeatureVersion, + pub store_reduced_platform_state: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveAbciLastBlockInfoStorageMethodVersions { + pub fetch_last_block_info: FeatureVersion, + pub store_last_block_info: FeatureVersion, +} + #[derive(Clone, Copy, Debug, Default)] pub struct DriveAbciEngineMethodVersions { pub init_chain: FeatureVersion, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v1.rs index 922358607b9..21d6bb57de2 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v1.rs @@ -6,8 +6,10 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciFeePoolInwardsDistributionMethodVersions, DriveAbciFeePoolOutwardsDistributionMethodVersions, DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, + DriveAbciLastBlockInfoStorageMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, + DriveAbciReducedPlatformStateStorageMethodVersions, DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, DriveAbciVotingMethodVersions, }; @@ -122,4 +124,12 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V1: DriveAbciMethodVersions = DriveAbciMeth fetch_platform_state: 0, store_platform_state: 0, }, + platform_reduced_state_storage: DriveAbciReducedPlatformStateStorageMethodVersions { + fetch_reduced_platform_state: 0, + store_reduced_platform_state: 0, + }, + last_block_info_storage: DriveAbciLastBlockInfoStorageMethodVersions { + fetch_last_block_info: 0, + store_last_block_info: 0, + }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v2.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v2.rs index fa1db356869..d189bf8d95f 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v2.rs @@ -6,8 +6,10 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciFeePoolInwardsDistributionMethodVersions, DriveAbciFeePoolOutwardsDistributionMethodVersions, DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, + DriveAbciLastBlockInfoStorageMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, + DriveAbciReducedPlatformStateStorageMethodVersions, DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, DriveAbciVotingMethodVersions, }; @@ -123,4 +125,12 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V2: DriveAbciMethodVersions = DriveAbciMeth fetch_platform_state: 0, store_platform_state: 0, }, + platform_reduced_state_storage: DriveAbciReducedPlatformStateStorageMethodVersions { + fetch_reduced_platform_state: 0, + store_reduced_platform_state: 0, + }, + last_block_info_storage: DriveAbciLastBlockInfoStorageMethodVersions { + fetch_last_block_info: 0, + store_last_block_info: 0, + }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v3.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v3.rs index c6439e23fdb..a9559ec30cf 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v3.rs @@ -6,8 +6,10 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciFeePoolInwardsDistributionMethodVersions, DriveAbciFeePoolOutwardsDistributionMethodVersions, DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, + DriveAbciLastBlockInfoStorageMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, + DriveAbciReducedPlatformStateStorageMethodVersions, DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, DriveAbciVotingMethodVersions, }; @@ -122,4 +124,12 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V3: DriveAbciMethodVersions = DriveAbciMeth fetch_platform_state: 0, store_platform_state: 0, }, + platform_reduced_state_storage: DriveAbciReducedPlatformStateStorageMethodVersions { + fetch_reduced_platform_state: 0, + store_reduced_platform_state: 0, + }, + last_block_info_storage: DriveAbciLastBlockInfoStorageMethodVersions { + fetch_last_block_info: 0, + store_last_block_info: 0, + }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v4.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v4.rs index b3d961563cd..1d4067f5110 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v4.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v4.rs @@ -6,8 +6,10 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciFeePoolInwardsDistributionMethodVersions, DriveAbciFeePoolOutwardsDistributionMethodVersions, DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, + DriveAbciLastBlockInfoStorageMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, + DriveAbciReducedPlatformStateStorageMethodVersions, DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, DriveAbciVotingMethodVersions, }; @@ -122,4 +124,12 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V4: DriveAbciMethodVersions = DriveAbciMeth fetch_platform_state: 0, store_platform_state: 0, }, + platform_reduced_state_storage: DriveAbciReducedPlatformStateStorageMethodVersions { + fetch_reduced_platform_state: 0, + store_reduced_platform_state: 0, + }, + last_block_info_storage: DriveAbciLastBlockInfoStorageMethodVersions { + fetch_last_block_info: 0, + store_last_block_info: 0, + }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs index 1490bd06ed9..66c1f335c36 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v5.rs @@ -6,8 +6,10 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciFeePoolInwardsDistributionMethodVersions, DriveAbciFeePoolOutwardsDistributionMethodVersions, DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, + DriveAbciLastBlockInfoStorageMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, + DriveAbciReducedPlatformStateStorageMethodVersions, DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, DriveAbciVotingMethodVersions, }; @@ -126,4 +128,12 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V5: DriveAbciMethodVersions = DriveAbciMeth fetch_platform_state: 0, store_platform_state: 0, }, + platform_reduced_state_storage: DriveAbciReducedPlatformStateStorageMethodVersions { + fetch_reduced_platform_state: 0, + store_reduced_platform_state: 0, + }, + last_block_info_storage: DriveAbciLastBlockInfoStorageMethodVersions { + fetch_last_block_info: 0, + store_last_block_info: 0, + }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v6.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v6.rs index 66754054a71..a0b934449b3 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v6.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_method_versions/v6.rs @@ -6,8 +6,10 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciFeePoolInwardsDistributionMethodVersions, DriveAbciFeePoolOutwardsDistributionMethodVersions, DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, + DriveAbciLastBlockInfoStorageMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, + DriveAbciReducedPlatformStateStorageMethodVersions, DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, DriveAbciVotingMethodVersions, }; @@ -17,7 +19,7 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V6: DriveAbciMethodVersions = DriveAbciMeth engine: DriveAbciEngineMethodVersions { init_chain: 0, check_tx: 0, - run_block_proposal: 0, + run_block_proposal: 1, finalize_block_proposal: 0, consensus_params_update: 1, }, @@ -124,4 +126,12 @@ pub const DRIVE_ABCI_METHOD_VERSIONS_V6: DriveAbciMethodVersions = DriveAbciMeth fetch_platform_state: 0, store_platform_state: 0, }, + platform_reduced_state_storage: DriveAbciReducedPlatformStateStorageMethodVersions { + fetch_reduced_platform_state: 0, + store_reduced_platform_state: 0, + }, + last_block_info_storage: DriveAbciLastBlockInfoStorageMethodVersions { + fetch_last_block_info: 0, + store_last_block_info: 0, + }, }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_state_sync_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_state_sync_versions/mod.rs new file mode 100644 index 00000000000..dc1104133b1 --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_state_sync_versions/mod.rs @@ -0,0 +1,8 @@ +pub mod v1; + +use versioned_feature_core::FeatureVersion; + +#[derive(Clone, Debug, Default)] +pub struct DriveAbciStateSyncVersions { + pub protocol_version: FeatureVersion, +} diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_state_sync_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_state_sync_versions/v1.rs new file mode 100644 index 00000000000..f5a3d13e884 --- /dev/null +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_state_sync_versions/v1.rs @@ -0,0 +1,6 @@ +use crate::version::drive_abci_versions::drive_abci_state_sync_versions::DriveAbciStateSyncVersions; + +pub const DRIVE_ABCI_STATE_SYNC_VERSIONS_V1: DriveAbciStateSyncVersions = + DriveAbciStateSyncVersions { + protocol_version: 1, + }; diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_structure_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_structure_versions/mod.rs index d00c9187ae9..6cb43f31be6 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_structure_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_structure_versions/mod.rs @@ -6,6 +6,7 @@ use versioned_feature_core::FeatureVersion; pub struct DriveAbciStructureVersions { pub platform_state_structure: FeatureVersion, pub platform_state_for_saving_structure_default: FeatureVersion, + pub reduced_platform_state_for_saving_structure_default: FeatureVersion, pub state_transition_execution_context: FeatureVersion, pub commit: FeatureVersion, pub masternode: FeatureVersion, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_structure_versions/v1.rs b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_structure_versions/v1.rs index b8e6725281b..3d045e0bf88 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_structure_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/drive_abci_structure_versions/v1.rs @@ -4,6 +4,7 @@ pub const DRIVE_ABCI_STRUCTURE_VERSIONS_V1: DriveAbciStructureVersions = DriveAbciStructureVersions { platform_state_structure: 0, platform_state_for_saving_structure_default: 0, + reduced_platform_state_for_saving_structure_default: 0, state_transition_execution_context: 0, commit: 0, masternode: 0, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions/mod.rs b/packages/rs-platform-version/src/version/drive_abci_versions/mod.rs index a6168ce9db6..38264e48c80 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions/mod.rs @@ -1,14 +1,17 @@ pub mod drive_abci_method_versions; pub mod drive_abci_query_versions; +pub mod drive_abci_state_sync_versions; pub mod drive_abci_structure_versions; pub mod drive_abci_validation_versions; pub mod drive_abci_withdrawal_constants; use drive_abci_method_versions::DriveAbciMethodVersions; use drive_abci_query_versions::DriveAbciQueryVersions; +use drive_abci_state_sync_versions::DriveAbciStateSyncVersions; use drive_abci_structure_versions::DriveAbciStructureVersions; use drive_abci_validation_versions::DriveAbciValidationVersions; use drive_abci_withdrawal_constants::DriveAbciWithdrawalConstants; + #[derive(Clone, Debug, Default)] pub struct DriveAbciVersion { pub structs: DriveAbciStructureVersions, @@ -16,4 +19,5 @@ pub struct DriveAbciVersion { pub validation_and_processing: DriveAbciValidationVersions, pub withdrawal_constants: DriveAbciWithdrawalConstants, pub query: DriveAbciQueryVersions, + pub state_sync: DriveAbciStateSyncVersions, } diff --git a/packages/rs-platform-version/src/version/drive_versions/mod.rs b/packages/rs-platform-version/src/version/drive_versions/mod.rs index dd5c1b1a155..e698f5d88ff 100644 --- a/packages/rs-platform-version/src/version/drive_versions/mod.rs +++ b/packages/rs-platform-version/src/version/drive_versions/mod.rs @@ -60,6 +60,8 @@ pub struct DriveMethodVersions { pub state_transitions: DriveStateTransitionMethodVersions, pub platform_state: DrivePlatformStateMethodVersions, pub group: DriveGroupMethodVersions, + pub reduced_platform_state: DriveReducedPlatformStateMethodVersions, + pub last_block_info: DriveLastBlockInfoMethodVersions, } #[derive(Clone, Debug, Default)] @@ -68,6 +70,18 @@ pub struct DrivePlatformStateMethodVersions { pub store_platform_state_bytes: FeatureVersion, } +#[derive(Clone, Debug, Default)] +pub struct DriveReducedPlatformStateMethodVersions { + pub fetch_reduced_platform_state_bytes: FeatureVersion, + pub store_reduced_platform_state_bytes: FeatureVersion, +} + +#[derive(Clone, Debug, Default)] +pub struct DriveLastBlockInfoMethodVersions { + pub fetch_last_block_info_bytes: FeatureVersion, + pub store_last_block_info_bytes: FeatureVersion, +} + #[derive(Clone, Debug, Default)] pub struct DriveDataContractOperationMethodVersions { pub finalization_tasks: FeatureVersion, diff --git a/packages/rs-platform-version/src/version/drive_versions/v1.rs b/packages/rs-platform-version/src/version/drive_versions/v1.rs index 1daae27b5b7..8f00dab0332 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v1.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v1.rs @@ -12,10 +12,12 @@ use crate::version::drive_versions::drive_vote_method_versions::v1::DRIVE_VOTE_M use crate::version::drive_versions::{ DriveAssetLockMethodVersions, DriveBalancesMethodVersions, DriveBatchOperationsMethodVersion, DriveEstimatedCostsMethodVersions, DriveFeesMethodVersions, DriveFetchMethodVersions, - DriveInitializationMethodVersions, DriveMethodVersions, DriveOperationsMethodVersion, - DrivePlatformStateMethodVersions, DrivePlatformSystemMethodVersions, - DrivePrefundedSpecializedMethodVersions, DriveProtocolUpgradeVersions, - DriveProveMethodVersions, DriveSystemEstimationCostsMethodVersions, DriveVersion, + DriveInitializationMethodVersions, DriveLastBlockInfoMethodVersions, DriveMethodVersions, + DriveOperationsMethodVersion, DrivePlatformStateMethodVersions, + DrivePlatformSystemMethodVersions, DrivePrefundedSpecializedMethodVersions, + DriveProtocolUpgradeVersions, DriveProveMethodVersions, + DriveReducedPlatformStateMethodVersions, DriveSystemEstimationCostsMethodVersions, + DriveVersion, }; use grovedb_version::version::v1::GROVE_V1; @@ -99,6 +101,14 @@ pub const DRIVE_VERSION_V1: DriveVersion = DriveVersion { empty_prefunded_specialized_balance: 0, }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, + reduced_platform_state: DriveReducedPlatformStateMethodVersions { + fetch_reduced_platform_state_bytes: 0, + store_reduced_platform_state_bytes: 0, + }, + last_block_info: DriveLastBlockInfoMethodVersions { + fetch_last_block_info_bytes: 0, + store_last_block_info_bytes: 0, + } }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1, diff --git a/packages/rs-platform-version/src/version/drive_versions/v2.rs b/packages/rs-platform-version/src/version/drive_versions/v2.rs index b76e79c7f97..0df52509a2e 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v2.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v2.rs @@ -12,10 +12,12 @@ use crate::version::drive_versions::drive_vote_method_versions::v2::DRIVE_VOTE_M use crate::version::drive_versions::{ DriveAssetLockMethodVersions, DriveBalancesMethodVersions, DriveBatchOperationsMethodVersion, DriveEstimatedCostsMethodVersions, DriveFeesMethodVersions, DriveFetchMethodVersions, - DriveInitializationMethodVersions, DriveMethodVersions, DriveOperationsMethodVersion, - DrivePlatformStateMethodVersions, DrivePlatformSystemMethodVersions, - DrivePrefundedSpecializedMethodVersions, DriveProtocolUpgradeVersions, - DriveProveMethodVersions, DriveSystemEstimationCostsMethodVersions, DriveVersion, + DriveInitializationMethodVersions, DriveLastBlockInfoMethodVersions, DriveMethodVersions, + DriveOperationsMethodVersion, DrivePlatformStateMethodVersions, + DrivePlatformSystemMethodVersions, DrivePrefundedSpecializedMethodVersions, + DriveProtocolUpgradeVersions, DriveProveMethodVersions, + DriveReducedPlatformStateMethodVersions, DriveSystemEstimationCostsMethodVersions, + DriveVersion, }; use grovedb_version::version::v1::GROVE_V1; @@ -99,6 +101,14 @@ pub const DRIVE_VERSION_V2: DriveVersion = DriveVersion { empty_prefunded_specialized_balance: 0, }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, + reduced_platform_state: DriveReducedPlatformStateMethodVersions { + fetch_reduced_platform_state_bytes: 0, + store_reduced_platform_state_bytes: 0, + }, + last_block_info: DriveLastBlockInfoMethodVersions { + fetch_last_block_info_bytes: 0, + store_last_block_info_bytes: 0, + } }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1, diff --git a/packages/rs-platform-version/src/version/drive_versions/v3.rs b/packages/rs-platform-version/src/version/drive_versions/v3.rs index 4af61e282eb..805a7d6fc71 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v3.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v3.rs @@ -12,10 +12,12 @@ use crate::version::drive_versions::drive_vote_method_versions::v2::DRIVE_VOTE_M use crate::version::drive_versions::{ DriveAssetLockMethodVersions, DriveBalancesMethodVersions, DriveBatchOperationsMethodVersion, DriveEstimatedCostsMethodVersions, DriveFeesMethodVersions, DriveFetchMethodVersions, - DriveInitializationMethodVersions, DriveMethodVersions, DriveOperationsMethodVersion, - DrivePlatformStateMethodVersions, DrivePlatformSystemMethodVersions, - DrivePrefundedSpecializedMethodVersions, DriveProtocolUpgradeVersions, - DriveProveMethodVersions, DriveSystemEstimationCostsMethodVersions, DriveVersion, + DriveInitializationMethodVersions, DriveLastBlockInfoMethodVersions, DriveMethodVersions, + DriveOperationsMethodVersion, DrivePlatformStateMethodVersions, + DrivePlatformSystemMethodVersions, DrivePrefundedSpecializedMethodVersions, + DriveProtocolUpgradeVersions, DriveProveMethodVersions, + DriveReducedPlatformStateMethodVersions, DriveSystemEstimationCostsMethodVersions, + DriveVersion, }; use grovedb_version::version::v1::GROVE_V1; @@ -99,6 +101,14 @@ pub const DRIVE_VERSION_V3: DriveVersion = DriveVersion { empty_prefunded_specialized_balance: 0, }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, + reduced_platform_state: DriveReducedPlatformStateMethodVersions { + fetch_reduced_platform_state_bytes: 0, + store_reduced_platform_state_bytes: 0, + }, + last_block_info: DriveLastBlockInfoMethodVersions { + fetch_last_block_info_bytes: 0, + store_last_block_info_bytes: 0, + } }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1, diff --git a/packages/rs-platform-version/src/version/drive_versions/v4.rs b/packages/rs-platform-version/src/version/drive_versions/v4.rs index 34af21d7d20..58564335519 100644 --- a/packages/rs-platform-version/src/version/drive_versions/v4.rs +++ b/packages/rs-platform-version/src/version/drive_versions/v4.rs @@ -12,10 +12,12 @@ use crate::version::drive_versions::drive_vote_method_versions::v2::DRIVE_VOTE_M use crate::version::drive_versions::{ DriveAssetLockMethodVersions, DriveBalancesMethodVersions, DriveBatchOperationsMethodVersion, DriveEstimatedCostsMethodVersions, DriveFeesMethodVersions, DriveFetchMethodVersions, - DriveInitializationMethodVersions, DriveMethodVersions, DriveOperationsMethodVersion, - DrivePlatformStateMethodVersions, DrivePlatformSystemMethodVersions, - DrivePrefundedSpecializedMethodVersions, DriveProtocolUpgradeVersions, - DriveProveMethodVersions, DriveSystemEstimationCostsMethodVersions, DriveVersion, + DriveInitializationMethodVersions, DriveLastBlockInfoMethodVersions, DriveMethodVersions, + DriveOperationsMethodVersion, DrivePlatformStateMethodVersions, + DrivePlatformSystemMethodVersions, DrivePrefundedSpecializedMethodVersions, + DriveProtocolUpgradeVersions, DriveProveMethodVersions, + DriveReducedPlatformStateMethodVersions, DriveSystemEstimationCostsMethodVersions, + DriveVersion, }; use grovedb_version::version::v2::GROVE_V2; @@ -99,6 +101,14 @@ pub const DRIVE_VERSION_V4: DriveVersion = DriveVersion { empty_prefunded_specialized_balance: 0, }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, + reduced_platform_state: DriveReducedPlatformStateMethodVersions { + fetch_reduced_platform_state_bytes: 0, + store_reduced_platform_state_bytes: 0, + }, + last_block_info: DriveLastBlockInfoMethodVersions { + fetch_last_block_info_bytes: 0, + store_last_block_info_bytes: 0, + } }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V2, //changed in V4 diff --git a/packages/rs-platform-version/src/version/mocks/v2_test.rs b/packages/rs-platform-version/src/version/mocks/v2_test.rs index e07f238d639..a3693ca075d 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -21,6 +21,7 @@ use crate::version::drive_abci_versions::drive_abci_query_versions::{ DriveAbciQuerySystemVersions, DriveAbciQueryTokenVersions, DriveAbciQueryValidatorVersions, DriveAbciQueryVersions, DriveAbciQueryVotingVersions, }; +use crate::version::drive_abci_versions::drive_abci_state_sync_versions::v1::DRIVE_ABCI_STATE_SYNC_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v1::DRIVE_ABCI_VALIDATION_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v1::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V1; @@ -39,10 +40,12 @@ use crate::version::drive_versions::drive_vote_method_versions::v1::DRIVE_VOTE_M use crate::version::drive_versions::{ DriveAssetLockMethodVersions, DriveBalancesMethodVersions, DriveBatchOperationsMethodVersion, DriveEstimatedCostsMethodVersions, DriveFeesMethodVersions, DriveFetchMethodVersions, - DriveInitializationMethodVersions, DriveMethodVersions, DriveOperationsMethodVersion, - DrivePlatformStateMethodVersions, DrivePlatformSystemMethodVersions, - DrivePrefundedSpecializedMethodVersions, DriveProtocolUpgradeVersions, - DriveProveMethodVersions, DriveSystemEstimationCostsMethodVersions, DriveVersion, + DriveInitializationMethodVersions, DriveLastBlockInfoMethodVersions, DriveMethodVersions, + DriveOperationsMethodVersion, DrivePlatformStateMethodVersions, + DrivePlatformSystemMethodVersions, DrivePrefundedSpecializedMethodVersions, + DriveProtocolUpgradeVersions, DriveProveMethodVersions, + DriveReducedPlatformStateMethodVersions, DriveSystemEstimationCostsMethodVersions, + DriveVersion, }; use crate::version::fee::v1::FEE_VERSION1; use crate::version::mocks::TEST_PROTOCOL_VERSION_SHIFT_BYTES; @@ -135,6 +138,14 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { empty_prefunded_specialized_balance: 0, }, group: DRIVE_GROUP_METHOD_VERSIONS_V1, + reduced_platform_state: DriveReducedPlatformStateMethodVersions { + fetch_reduced_platform_state_bytes: 0, + store_reduced_platform_state_bytes: 0, + }, + last_block_info: DriveLastBlockInfoMethodVersions { + fetch_last_block_info_bytes: 0, + store_last_block_info_bytes: 0, + } }, grove_methods: DRIVE_GROVE_METHOD_VERSIONS_V1, grove_version: GROVE_V1, @@ -375,6 +386,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { }, }, }, + state_sync: DRIVE_ABCI_STATE_SYNC_VERSIONS_V1, }, dpp: DPPVersion { costs: DPP_COSTS_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/mocks/v3_test.rs b/packages/rs-platform-version/src/version/mocks/v3_test.rs index 3a8964266da..0dbc229a10d 100644 --- a/packages/rs-platform-version/src/version/mocks/v3_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v3_test.rs @@ -22,12 +22,15 @@ use crate::version::drive_abci_versions::drive_abci_method_versions::{ DriveAbciFeePoolInwardsDistributionMethodVersions, DriveAbciFeePoolOutwardsDistributionMethodVersions, DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, + DriveAbciLastBlockInfoStorageMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, DriveAbciPlatformStateStorageMethodVersions, DriveAbciProtocolUpgradeMethodVersions, + DriveAbciReducedPlatformStateStorageMethodVersions, DriveAbciStateTransitionProcessingMethodVersions, DriveAbciTokensProcessingMethodVersions, DriveAbciVotingMethodVersions, }; use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; +use crate::version::drive_abci_versions::drive_abci_state_sync_versions::v1::DRIVE_ABCI_STATE_SYNC_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v3::DRIVE_ABCI_VALIDATION_VERSIONS_V3; use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v2::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2; @@ -50,7 +53,7 @@ pub const TEST_PLATFORM_V3: PlatformVersion = PlatformVersion { engine: DriveAbciEngineMethodVersions { init_chain: 0, check_tx: 0, - run_block_proposal: 0, + run_block_proposal: 1, finalize_block_proposal: 0, consensus_params_update: 1, }, @@ -156,10 +159,19 @@ pub const TEST_PLATFORM_V3: PlatformVersion = PlatformVersion { fetch_platform_state: 0, store_platform_state: 0, }, + platform_reduced_state_storage: DriveAbciReducedPlatformStateStorageMethodVersions { + fetch_reduced_platform_state: 0, + store_reduced_platform_state: 0, + }, + last_block_info_storage: DriveAbciLastBlockInfoStorageMethodVersions { + fetch_last_block_info: 0, + store_last_block_info: 0, + }, }, validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V3, withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2, query: DRIVE_ABCI_QUERY_VERSIONS_V1, + state_sync: DRIVE_ABCI_STATE_SYNC_VERSIONS_V1, }, dpp: DPPVersion { costs: DPP_COSTS_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v1.rs b/packages/rs-platform-version/src/version/v1.rs index 5f32d406fae..be2680d40d9 100644 --- a/packages/rs-platform-version/src/version/v1.rs +++ b/packages/rs-platform-version/src/version/v1.rs @@ -16,6 +16,7 @@ use crate::version::dpp_versions::dpp_voting_versions::v1::VOTING_VERSION_V1; use crate::version::dpp_versions::DPPVersion; use crate::version::drive_abci_versions::drive_abci_method_versions::v1::DRIVE_ABCI_METHOD_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; +use crate::version::drive_abci_versions::drive_abci_state_sync_versions::v1::DRIVE_ABCI_STATE_SYNC_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v1::DRIVE_ABCI_VALIDATION_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v1::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V1; @@ -38,6 +39,7 @@ pub const PLATFORM_V1: PlatformVersion = PlatformVersion { validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V1, withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V1, query: DRIVE_ABCI_QUERY_VERSIONS_V1, + state_sync: DRIVE_ABCI_STATE_SYNC_VERSIONS_V1, }, dpp: DPPVersion { costs: DPP_COSTS_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v2.rs b/packages/rs-platform-version/src/version/v2.rs index f97bee41394..f2a4b19cc0e 100644 --- a/packages/rs-platform-version/src/version/v2.rs +++ b/packages/rs-platform-version/src/version/v2.rs @@ -16,6 +16,7 @@ use crate::version::dpp_versions::dpp_voting_versions::v1::VOTING_VERSION_V1; use crate::version::dpp_versions::DPPVersion; use crate::version::drive_abci_versions::drive_abci_method_versions::v1::DRIVE_ABCI_METHOD_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; +use crate::version::drive_abci_versions::drive_abci_state_sync_versions::v1::DRIVE_ABCI_STATE_SYNC_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v2::DRIVE_ABCI_VALIDATION_VERSIONS_V2; use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v1::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V1; @@ -38,6 +39,7 @@ pub const PLATFORM_V2: PlatformVersion = PlatformVersion { validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V2, withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V1, query: DRIVE_ABCI_QUERY_VERSIONS_V1, + state_sync: DRIVE_ABCI_STATE_SYNC_VERSIONS_V1, }, dpp: DPPVersion { costs: DPP_COSTS_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v3.rs b/packages/rs-platform-version/src/version/v3.rs index ddc624c26cb..726aa91b7ac 100644 --- a/packages/rs-platform-version/src/version/v3.rs +++ b/packages/rs-platform-version/src/version/v3.rs @@ -16,6 +16,7 @@ use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; use crate::version::drive_abci_versions::drive_abci_method_versions::v2::DRIVE_ABCI_METHOD_VERSIONS_V2; use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; +use crate::version::drive_abci_versions::drive_abci_state_sync_versions::v1::DRIVE_ABCI_STATE_SYNC_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v2::DRIVE_ABCI_VALIDATION_VERSIONS_V2; use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v1::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V1; @@ -44,6 +45,7 @@ pub const PLATFORM_V3: PlatformVersion = PlatformVersion { validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V2, withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V1, query: DRIVE_ABCI_QUERY_VERSIONS_V1, + state_sync: DRIVE_ABCI_STATE_SYNC_VERSIONS_V1, }, dpp: DPPVersion { costs: DPP_COSTS_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v4.rs b/packages/rs-platform-version/src/version/v4.rs index ccc19920d2d..7f8da613aa5 100644 --- a/packages/rs-platform-version/src/version/v4.rs +++ b/packages/rs-platform-version/src/version/v4.rs @@ -16,6 +16,7 @@ use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; use crate::version::drive_abci_versions::drive_abci_method_versions::v3::DRIVE_ABCI_METHOD_VERSIONS_V3; use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; +use crate::version::drive_abci_versions::drive_abci_state_sync_versions::v1::DRIVE_ABCI_STATE_SYNC_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v3::DRIVE_ABCI_VALIDATION_VERSIONS_V3; use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v2::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2; @@ -39,6 +40,7 @@ pub const PLATFORM_V4: PlatformVersion = PlatformVersion { validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V3, withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2, query: DRIVE_ABCI_QUERY_VERSIONS_V1, + state_sync: DRIVE_ABCI_STATE_SYNC_VERSIONS_V1, }, dpp: DPPVersion { costs: DPP_COSTS_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v5.rs b/packages/rs-platform-version/src/version/v5.rs index 1b2cda5a53c..741531e8aae 100644 --- a/packages/rs-platform-version/src/version/v5.rs +++ b/packages/rs-platform-version/src/version/v5.rs @@ -16,6 +16,7 @@ use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; use crate::version::drive_abci_versions::drive_abci_method_versions::v4::DRIVE_ABCI_METHOD_VERSIONS_V4; use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; +use crate::version::drive_abci_versions::drive_abci_state_sync_versions::v1::DRIVE_ABCI_STATE_SYNC_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v3::DRIVE_ABCI_VALIDATION_VERSIONS_V3; use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v2::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2; @@ -39,6 +40,7 @@ pub const PLATFORM_V5: PlatformVersion = PlatformVersion { validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V3, withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2, query: DRIVE_ABCI_QUERY_VERSIONS_V1, + state_sync: DRIVE_ABCI_STATE_SYNC_VERSIONS_V1, }, dpp: DPPVersion { costs: DPP_COSTS_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v6.rs b/packages/rs-platform-version/src/version/v6.rs index 3ae597d99f7..6a97bd60f1e 100644 --- a/packages/rs-platform-version/src/version/v6.rs +++ b/packages/rs-platform-version/src/version/v6.rs @@ -16,6 +16,7 @@ use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; use crate::version::drive_abci_versions::drive_abci_method_versions::v4::DRIVE_ABCI_METHOD_VERSIONS_V4; use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; +use crate::version::drive_abci_versions::drive_abci_state_sync_versions::v1::DRIVE_ABCI_STATE_SYNC_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v4::DRIVE_ABCI_VALIDATION_VERSIONS_V4; use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v2::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2; @@ -39,6 +40,7 @@ pub const PLATFORM_V6: PlatformVersion = PlatformVersion { validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V4, // Changed to version 4 withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2, query: DRIVE_ABCI_QUERY_VERSIONS_V1, + state_sync: DRIVE_ABCI_STATE_SYNC_VERSIONS_V1, }, dpp: DPPVersion { costs: DPP_COSTS_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v7.rs b/packages/rs-platform-version/src/version/v7.rs index 1c1824b3203..1a296a44674 100644 --- a/packages/rs-platform-version/src/version/v7.rs +++ b/packages/rs-platform-version/src/version/v7.rs @@ -16,6 +16,7 @@ use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; use crate::version::drive_abci_versions::drive_abci_method_versions::v4::DRIVE_ABCI_METHOD_VERSIONS_V4; use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; +use crate::version::drive_abci_versions::drive_abci_state_sync_versions::v1::DRIVE_ABCI_STATE_SYNC_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v5::DRIVE_ABCI_VALIDATION_VERSIONS_V5; use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v2::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2; @@ -39,6 +40,7 @@ pub const PLATFORM_V7: PlatformVersion = PlatformVersion { validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V5, // <--- changed to V5 withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2, query: DRIVE_ABCI_QUERY_VERSIONS_V1, + state_sync: DRIVE_ABCI_STATE_SYNC_VERSIONS_V1, }, dpp: DPPVersion { costs: DPP_COSTS_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v8.rs b/packages/rs-platform-version/src/version/v8.rs index 9b6e7eff5ac..7fb7ba20a71 100644 --- a/packages/rs-platform-version/src/version/v8.rs +++ b/packages/rs-platform-version/src/version/v8.rs @@ -16,6 +16,7 @@ use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; use crate::version::drive_abci_versions::drive_abci_method_versions::v5::DRIVE_ABCI_METHOD_VERSIONS_V5; use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; +use crate::version::drive_abci_versions::drive_abci_state_sync_versions::v1::DRIVE_ABCI_STATE_SYNC_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v5::DRIVE_ABCI_VALIDATION_VERSIONS_V5; use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v2::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2; @@ -43,6 +44,7 @@ pub const PLATFORM_V8: PlatformVersion = PlatformVersion { validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V5, withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2, query: DRIVE_ABCI_QUERY_VERSIONS_V1, + state_sync: DRIVE_ABCI_STATE_SYNC_VERSIONS_V1, }, dpp: DPPVersion { costs: DPP_COSTS_VERSIONS_V1, diff --git a/packages/rs-platform-version/src/version/v9.rs b/packages/rs-platform-version/src/version/v9.rs index aebd1ca30bd..07ca401d4cb 100644 --- a/packages/rs-platform-version/src/version/v9.rs +++ b/packages/rs-platform-version/src/version/v9.rs @@ -16,6 +16,7 @@ use crate::version::dpp_versions::dpp_voting_versions::v2::VOTING_VERSION_V2; use crate::version::dpp_versions::DPPVersion; use crate::version::drive_abci_versions::drive_abci_method_versions::v6::DRIVE_ABCI_METHOD_VERSIONS_V6; use crate::version::drive_abci_versions::drive_abci_query_versions::v1::DRIVE_ABCI_QUERY_VERSIONS_V1; +use crate::version::drive_abci_versions::drive_abci_state_sync_versions::v1::DRIVE_ABCI_STATE_SYNC_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_structure_versions::v1::DRIVE_ABCI_STRUCTURE_VERSIONS_V1; use crate::version::drive_abci_versions::drive_abci_validation_versions::v6::DRIVE_ABCI_VALIDATION_VERSIONS_V6; use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v2::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2; @@ -40,6 +41,7 @@ pub const PLATFORM_V9: PlatformVersion = PlatformVersion { validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V6, // changed withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2, query: DRIVE_ABCI_QUERY_VERSIONS_V1, + state_sync: DRIVE_ABCI_STATE_SYNC_VERSIONS_V1, }, dpp: DPPVersion { costs: DPP_COSTS_VERSIONS_V1,