Skip to content

Commit

Permalink
feat(drive): platform version patching and state migrations (#1941)
Browse files Browse the repository at this point in the history
  • Loading branch information
shumkov authored Jul 16, 2024
1 parent 86b7b39 commit 257be50
Show file tree
Hide file tree
Showing 43 changed files with 853 additions and 103 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/rs-drive-abci/src/abci/handler/check_tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::error::execution::ExecutionError;
use crate::error::Error;
use crate::metrics::{LABEL_ABCI_RESPONSE_CODE, LABEL_CHECK_TX_MODE, LABEL_STATE_TRANSITION_NAME};
use crate::platform_types::platform::{Platform, PlatformRef};
use crate::platform_types::platform_state::v0::PlatformStateV0Methods;
use crate::rpc::core::CoreRPCLike;
use dpp::consensus::codes::ErrorWithCode;
use dpp::fee::SignedCredits;
Expand Down
1 change: 1 addition & 0 deletions packages/rs-drive-abci/src/abci/handler/finalize_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use crate::error::execution::ExecutionError;
use crate::error::Error;
use crate::execution::types::block_execution_context::v0::BlockExecutionContextV0Getters;
use crate::platform_types::cleaned_abci_messages::finalized_block_cleaned_request::v0::FinalizeBlockCleanedRequest;
use crate::platform_types::platform_state::v0::PlatformStateV0Methods;
use crate::rpc::core::CoreRPCLike;
use std::sync::atomic::Ordering;
use tenderdash_abci::proto::abci as proto;
Expand Down
8 changes: 2 additions & 6 deletions packages/rs-drive-abci/src/abci/handler/prepare_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ use crate::platform_types::platform_state::v0::PlatformStateV0Methods;
use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult;
use crate::rpc::core::CoreRPCLike;
use dpp::dashcore::hashes::Hash;
use dpp::version::PlatformVersion;
use dpp::version::TryIntoPlatformVersioned;
use tenderdash_abci::proto::abci as proto;
use tenderdash_abci::proto::abci::tx_record::TxAction;
Expand Down Expand Up @@ -117,13 +116,10 @@ where
app_hash,
state_transitions_result,
validator_set_update,
protocol_version,
platform_version,
mut block_execution_context,
} = run_result.into_data().map_err(Error::Protocol)?;

let platform_version = PlatformVersion::get(protocol_version)
.expect("must be set in run block proposal from existing protocol version");

// We need to let Tenderdash know about the transactions we should remove from execution
let valid_tx_count = state_transitions_result.valid_count();
let failed_tx_count = state_transitions_result.failed_count();
Expand Down Expand Up @@ -192,7 +188,7 @@ where
validator_set_update,
// TODO: implement consensus param updates
consensus_param_updates: None,
app_version: protocol_version as u64,
app_version: platform_version.protocol_version as u64,
};

block_execution_context.set_proposer_results(Some(response.clone()));
Expand Down
5 changes: 1 addition & 4 deletions packages/rs-drive-abci/src/abci/handler/process_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,10 @@ where
app_hash,
state_transitions_result: state_transition_results,
validator_set_update,
protocol_version,
platform_version,
block_execution_context,
} = run_result.into_data().map_err(Error::Protocol)?;

let platform_version = PlatformVersion::get(protocol_version)
.expect("must be set in run block proposer from existing platform version");

app.block_execution_context()
.write()
.unwrap()
Expand Down
1 change: 1 addition & 0 deletions packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ where
&platform_ref,
state_transition,
check_tx_level,
platform_version,
)?;

// If there are any validation errors happen we return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,19 @@ where
last_committed_platform_version,
)?;

// Determine a protocol version for this block
let platform_version = if epoch_info.is_epoch_change_but_not_genesis() {
// Create a bock state from previous committed state
let mut block_platform_state = platform_state.clone();

// Determine a platform version for this block
let block_platform_version = if epoch_info.is_epoch_change_but_not_genesis()
&& platform_state.next_epoch_protocol_version()
!= platform_state.current_protocol_version_in_consensus()
{
// Switch to next proposed platform version if we are on the first block of the new epoch
// This version must be set to the state as current one during block processing
// and the next protocol version (locked in the previous epoch) is different from the
// current protocol version.
// This version will be set to the block state, and we decide on next version for next epoch
// during block processing
let next_protocol_version = platform_state.next_epoch_protocol_version();

// We should panic if this node is not supported a new protocol version
Expand All @@ -80,13 +89,31 @@ Your software version: {}, latest supported protocol version: {}."#,
);
};

// Set current protocol version to the block platform state
block_platform_state.set_current_protocol_version_in_consensus(next_protocol_version);

next_platform_version
} else {
// Stay on the last committed platform version
last_committed_platform_version
};

match platform_version
// Patch platform version and run migrations if we have patches and/or
// migrations defined for this height.
// It modifies the protocol version to function version mapping to apply hotfixes
// Also it performs migrations to fix corrupted state or prepare it for new features
let block_platform_version = if let Some(patched_platform_version) = self
.apply_platform_version_patch_and_migrate_state_for_height(
block_proposal.height,
&mut block_platform_state,
transaction,
)? {
patched_platform_version
} else {
block_platform_version
};

match block_platform_version
.drive_abci
.methods
.engine
Expand All @@ -98,7 +125,8 @@ Your software version: {}, latest supported protocol version: {}."#,
epoch_info,
transaction,
platform_state,
platform_version,
block_platform_state,
block_platform_version,
),
version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch {
method: "run_block_proposal".to_string(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ where
epoch_info: EpochInfo,
transaction: &Transaction,
last_committed_platform_state: &PlatformState,
platform_version: &PlatformVersion,
mut block_platform_state: PlatformState,
platform_version: &'static PlatformVersion,
) -> Result<ValidationResult<block_execution_outcome::v0::BlockExecutionOutcome, Error>, Error>
{
tracing::trace!(
Expand Down Expand Up @@ -102,9 +103,6 @@ where
let last_block_core_height = last_committed_platform_state
.last_committed_known_core_height_or(self.config.abci.genesis_core_height);

// Create a bock state from previous committed state
let mut block_platform_state = last_committed_platform_state.clone();

// Init block execution context
let block_state_info = block_state_info::v0::BlockStateInfoV0::from_block_proposal(
&block_proposal,
Expand Down Expand Up @@ -388,7 +386,7 @@ where
app_hash: root_hash,
state_transitions_result,
validator_set_update,
protocol_version: platform_version.protocol_version,
platform_version,
block_execution_context,
},
))
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use crate::error::Error;

use dpp::prelude::BlockHeight;
use drive::grovedb::Transaction;

use crate::platform_types::platform::Platform;

use crate::platform_types::platform_state::PlatformState;

impl<C> Platform<C> {
/// Perform state migration based on block height
pub fn migrate_state_for_height(
&self,
height: BlockHeight,
_block_platform_state: &mut PlatformState,
_transaction: &Transaction,
) -> Result<(), Error> {
#[allow(clippy::match_single_binding)]
let is_migrated = match height {
// 30 => self.migration_30_test(block_platform_state, transaction)?,
_ => false,
};

if is_migrated {
tracing::debug!("Successfully migrated state for height {}", height);
}

Ok(())
}
}
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
/// Clearing the drive cache should happen when a new block is going to be run
pub(in crate::execution) mod clear_drive_block_cache;
/// State migration
mod migrate_state;
/// Patch the platform version function mapping and migrate state based on the block height
pub(in crate::execution) mod patch_platform;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
use crate::error::Error;
use crate::platform_types::platform::Platform;
use crate::platform_types::platform_state::PlatformState;
use dpp::prelude::BlockHeight;
use dpp::version::PlatformVersion;
use drive::grovedb::Transaction;

impl<C> Platform<C> {
/// This function patches platform version and run migrations
/// It modifies protocol version to function version mapping to apply hotfixes
/// Also it performs migrations to fix corrupted state or prepare it for new features
///
/// This function appends the patch to PlatformState, potentially alter Drive and Platform execution state
/// and returns patched version
pub fn apply_platform_version_patch_and_migrate_state_for_height(
&self,
height: BlockHeight,
platform_state: &mut PlatformState,
transaction: &Transaction,
) -> Result<Option<&'static PlatformVersion>, Error> {
let patched_platform_version =
platform_state.apply_platform_version_patch_for_height(height)?;

self.migrate_state_for_height(height, platform_state, transaction)?;

Ok(patched_platform_version)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ impl<C> Platform<C> {
#[cfg(test)]
mod tests {
use super::*;
use crate::platform_types::platform_state::v0::PlatformStateV0Methods;

mod add_epoch_pool_to_proposers_payout_operations {
use super::*;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,6 @@ impl<C> Platform<C> {
previous_block_protocol_version,
current_block_protocol_version,
);

block_platform_state
.set_current_protocol_version_in_consensus(current_block_protocol_version);
};

// Determine a new protocol version for the next epoch if enough proposers voted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::platform_types::platform::PlatformRef;
use crate::rpc::core::CoreRPCLike;
use dpp::prelude::ConsensusValidationResult;
use dpp::state_transition::StateTransition;
use dpp::version::PlatformVersion;

use crate::execution::check_tx::CheckTxLevel;

Expand All @@ -25,8 +26,8 @@ pub(in crate::execution) fn state_transition_to_execution_event_for_check_tx<'a,
platform: &'a PlatformRef<C>,
state_transition: StateTransition,
check_tx_level: CheckTxLevel,
platform_version: &PlatformVersion,
) -> Result<ConsensusValidationResult<Option<ExecutionEvent<'a>>>, Error> {
let platform_version = platform.state.current_platform_version()?;
match platform_version
.drive_abci
.validation_and_processing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use dpp::block::block_info::BlockInfo;
use dpp::prelude::ConsensusValidationResult;
use dpp::state_transition::StateTransition;

use crate::platform_types::platform_state::v0::PlatformStateV0Methods;
use drive::grovedb::TransactionArg;

/// There are multiple stages in a state transition processing:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use crate::execution::validation::state_transition::processor::v0::{
};
use crate::execution::validation::state_transition::transformer::StateTransitionActionTransformerV0;
use crate::execution::validation::state_transition::ValidationMode;
use crate::platform_types::platform_state::v0::PlatformStateV0Methods;

impl ValidationMode {
/// Returns if we should validate the contract when we transform it from its serialized form
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use crate::execution::validation::state_transition::data_contract_update::state:
use crate::execution::validation::state_transition::transformer::StateTransitionActionTransformerV0;
use crate::execution::validation::state_transition::ValidationMode;
use crate::platform_types::platform::PlatformRef;
use crate::platform_types::platform_state::v0::PlatformStateV0Methods;
use crate::rpc::core::CoreRPCLike;

impl StateTransitionActionTransformerV0 for DataContractUpdateTransition {
Expand Down Expand Up @@ -78,6 +79,7 @@ mod tests {
DataContractUpdateTransition, DataContractUpdateTransitionV0,
};

use crate::platform_types::platform_state::v0::PlatformStateV0Methods;
use crate::platform_types::state_transitions_processing_result::StateTransitionExecutionResult;
use dpp::tests::fixtures::get_data_contract_fixture;
use dpp::tests::json_document::json_document_to_contract;
Expand Down Expand Up @@ -577,9 +579,8 @@ mod tests {

let card_game_path = "tests/supporting_files/contract/crypto-card-game/crypto-card-game-direct-purchase-creation-restricted-to-owner.json";

let platform_version = platform
.state
.load()
let platform_state = platform.state.load();
let platform_version = platform_state
.current_platform_version()
.expect("expected to get current platform version");

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use crate::execution::validation::state_transition::data_contract_update::state:
use crate::execution::validation::state_transition::processor::v0::StateTransitionStateValidationV0;
use crate::execution::validation::state_transition::ValidationMode;
use crate::platform_types::platform::PlatformRef;
use crate::platform_types::platform_state::v0::PlatformStateV0Methods;
use crate::rpc::core::CoreRPCLike;
use dpp::block::block_info::BlockInfo;
use dpp::state_transition::data_contract_update_transition::DataContractUpdateTransition;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ mod tests {
use dpp::withdrawal::Pooling;
use drive::drive::contract::DataContractFetchInfo;
use crate::execution::types::state_transition_execution_context::v0::StateTransitionExecutionContextV0;
use crate::platform_types::platform_state::v0::PlatformStateV0Methods;

#[test]
fn should_throw_error_if_withdrawal_not_found() {
Expand Down
Loading

0 comments on commit 257be50

Please sign in to comment.