Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix!: emergency hard fork to fix masternode voting #2397

Merged
merged 3 commits into from
Dec 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use crate::error::execution::ExecutionError;
use crate::error::Error;
use crate::execution::types::state_transition_execution_context::StateTransitionExecutionContext;
use crate::execution::validation::state_transition::masternode_vote::nonce::v0::MasternodeVoteTransitionIdentityNonceV0;
use crate::execution::validation::state_transition::masternode_vote::nonce::v1::MasternodeVoteTransitionIdentityNonceV1;
use crate::execution::validation::state_transition::processor::v0::StateTransitionNonceValidationV0;
use crate::platform_types::platform::PlatformStateRef;
use dpp::block::block_info::BlockInfo;
Expand All @@ -11,6 +12,8 @@ use dpp::version::PlatformVersion;
use drive::grovedb::TransactionArg;

pub(crate) mod v0;
pub(crate) mod v1;

impl StateTransitionNonceValidationV0 for MasternodeVoteTransition {
fn validate_nonces(
&self,
Expand All @@ -34,14 +37,21 @@ impl StateTransitionNonceValidationV0 for MasternodeVoteTransition {
execution_context,
platform_version,
),
Some(1) => self.validate_nonce_v1(
platform,
block_info,
tx,
execution_context,
platform_version,
),
Some(version) => Err(Error::Execution(ExecutionError::UnknownVersionMismatch {
method: "masternode vote transition: validate_nonces".to_string(),
known_versions: vec![0],
known_versions: vec![0, 1],
received: version,
})),
None => Err(Error::Execution(ExecutionError::VersionNotActive {
method: "masternode vote transition: validate_nonces".to_string(),
known_versions: vec![0],
known_versions: vec![0, 1],
})),
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::execution::types::execution_operation::ValidationOperation;
use crate::execution::types::state_transition_execution_context::{
StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0,
};
use crate::execution::validation::state_transition::masternode_vote::nonce::v1::MasternodeVoteTransitionIdentityNonceV1;
use crate::platform_types::platform::PlatformStateRef;
use dpp::version::PlatformVersion;
use drive::grovedb::TransactionArg;
Expand All @@ -39,6 +40,17 @@ impl MasternodeVoteTransitionIdentityNonceV0 for MasternodeVoteTransition {
execution_context: &mut StateTransitionExecutionContext,
platform_version: &PlatformVersion,
) -> Result<SimpleConsensusValidationResult, Error> {
// We are introducing this as an emergency hard fork activating at epoch 13.
if block_info.epoch.index >= 13 {
return self.validate_nonce_v1(
platform,
block_info,
tx,
execution_context,
platform_version,
);
}

let revision_nonce = self.nonce();

if revision_nonce & MISSING_IDENTITY_REVISIONS_FILTER > 0 {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
use crate::error::Error;
use dpp::block::block_info::BlockInfo;
use dpp::consensus::basic::document::NonceOutOfBoundsError;
use dpp::consensus::basic::BasicError;
use dpp::identity::identity_nonce::{
validate_identity_nonce_update, validate_new_identity_nonce, MISSING_IDENTITY_REVISIONS_FILTER,
};
use dpp::state_transition::masternode_vote_transition::accessors::MasternodeVoteTransitionAccessorsV0;
use dpp::state_transition::masternode_vote_transition::MasternodeVoteTransition;

use dpp::validation::SimpleConsensusValidationResult;

use crate::execution::types::execution_operation::ValidationOperation;
use crate::execution::types::state_transition_execution_context::{
StateTransitionExecutionContext, StateTransitionExecutionContextMethodsV0,
};
use crate::platform_types::platform::PlatformStateRef;
use dpp::version::PlatformVersion;
use drive::grovedb::TransactionArg;

pub(in crate::execution::validation::state_transition::state_transitions) trait MasternodeVoteTransitionIdentityNonceV1
{
fn validate_nonce_v1(
&self,
platform: &PlatformStateRef,
block_info: &BlockInfo,
tx: TransactionArg,
execution_context: &mut StateTransitionExecutionContext,
platform_version: &PlatformVersion,
) -> Result<SimpleConsensusValidationResult, Error>;
}

impl MasternodeVoteTransitionIdentityNonceV1 for MasternodeVoteTransition {
fn validate_nonce_v1(
&self,
platform: &PlatformStateRef,
block_info: &BlockInfo,
tx: TransactionArg,
execution_context: &mut StateTransitionExecutionContext,
platform_version: &PlatformVersion,
) -> Result<SimpleConsensusValidationResult, Error> {
let revision_nonce = self.nonce();

if revision_nonce & MISSING_IDENTITY_REVISIONS_FILTER > 0 {
return Ok(SimpleConsensusValidationResult::new_with_error(
BasicError::NonceOutOfBoundsError(NonceOutOfBoundsError::new(revision_nonce))
.into(),
));
}

let voter_identity_id = self.voter_identity_id();

let (existing_nonce, fee) = platform.drive.fetch_identity_nonce_with_fees(
voter_identity_id.to_buffer(),
block_info,
true,
tx,
platform_version,
)?;

execution_context.add_operation(ValidationOperation::PrecalculatedOperation(fee));

let result = if let Some(existing_nonce) = existing_nonce {
validate_identity_nonce_update(existing_nonce, revision_nonce, voter_identity_id)
} else {
validate_new_identity_nonce(revision_nonce, voter_identity_id)
};

Ok(result)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod v1;
pub mod v2;
pub mod v3;
pub mod v4;
pub mod v5;

use versioned_feature_core::{FeatureVersion, OptionalFeatureVersion};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use crate::version::drive_abci_versions::drive_abci_validation_versions::{
DriveAbciValidationVersions, PenaltyAmounts,
};

// We introduced nonce validation for masternode voting in this version, and changed the call
// for nonce validation, however the actual validation for masternode voting was faulty, which is
// why we introduced V5. (We also are making an emergency hard fork).
pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions =
DriveAbciValidationVersions {
state_transitions: DriveAbciStateTransitionValidationVersions {
Expand Down Expand Up @@ -131,7 +134,7 @@ pub const DRIVE_ABCI_VALIDATION_VERSIONS_V4: DriveAbciValidationVersions =
document_update_price_transition_state_validation: 0,
},
},
has_nonce_validation: 1,
has_nonce_validation: 1, // <---- changed this
process_state_transition: 0,
state_transition_to_execution_event_for_check_tx: 0,
penalties: PenaltyAmounts {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use crate::version::drive_abci_versions::drive_abci_validation_versions::{
DriveAbciAssetLockValidationVersions, DriveAbciDocumentsStateTransitionValidationVersions,
DriveAbciStateTransitionCommonValidationVersions, DriveAbciStateTransitionValidationVersion,
DriveAbciStateTransitionValidationVersions, DriveAbciValidationConstants,
DriveAbciValidationDataTriggerAndBindingVersions, DriveAbciValidationDataTriggerVersions,
DriveAbciValidationVersions, PenaltyAmounts,
};

// In this version we change the nonce validation of masternode voting.
// There was a bug before this where the nonce validation would validate using the owner identity
// instead of the voting identity.
// This is not the same issue as before when we didn't validate nonces on masternode votes at all.
pub const DRIVE_ABCI_VALIDATION_VERSIONS_V5: DriveAbciValidationVersions =
DriveAbciValidationVersions {
state_transitions: DriveAbciStateTransitionValidationVersions {
common_validation_methods: DriveAbciStateTransitionCommonValidationVersions {
asset_locks: DriveAbciAssetLockValidationVersions {
fetch_asset_lock_transaction_output_sync: 0,
verify_asset_lock_is_not_spent_and_has_enough_balance: 0,
},
validate_identity_public_key_contract_bounds: 0,
validate_identity_public_key_ids_dont_exist_in_state: 0,
validate_identity_public_key_ids_exist_in_state: 0,
validate_state_transition_identity_signed: 0,
validate_unique_identity_public_key_hashes_in_state: 0,
validate_master_key_uniqueness: 0,
validate_simple_pre_check_balance: 0,
},
max_asset_lock_usage_attempts: 16,
identity_create_state_transition: DriveAbciStateTransitionValidationVersion {
basic_structure: Some(0),
advanced_structure: Some(0),
identity_signatures: Some(0),
advanced_minimum_balance_pre_check: None,
nonce: None,
state: 0,
transform_into_action: 0,
},
identity_update_state_transition: DriveAbciStateTransitionValidationVersion {
basic_structure: Some(0),
advanced_structure: Some(0),
identity_signatures: Some(0),
advanced_minimum_balance_pre_check: None,
nonce: Some(0),
state: 0,
transform_into_action: 0,
},
identity_top_up_state_transition: DriveAbciStateTransitionValidationVersion {
basic_structure: Some(0),
advanced_structure: None,
identity_signatures: None,
advanced_minimum_balance_pre_check: None,
nonce: None,
state: 0,
transform_into_action: 0,
},
identity_credit_withdrawal_state_transition:
DriveAbciStateTransitionValidationVersion {
basic_structure: Some(1),
advanced_structure: None,
identity_signatures: None,
advanced_minimum_balance_pre_check: Some(0),
nonce: Some(0),
state: 0,
transform_into_action: 0,
},
identity_credit_withdrawal_state_transition_purpose_matches_requirements: 0,
identity_credit_transfer_state_transition: DriveAbciStateTransitionValidationVersion {
basic_structure: Some(0),
advanced_structure: None,
identity_signatures: None,
advanced_minimum_balance_pre_check: Some(0),
nonce: Some(0),
state: 0,
transform_into_action: 0,
},
masternode_vote_state_transition: DriveAbciStateTransitionValidationVersion {
basic_structure: None,
advanced_structure: Some(0),
identity_signatures: None,
advanced_minimum_balance_pre_check: Some(0),
nonce: Some(1), // <---- Changed this here
state: 0,
transform_into_action: 0,
},
contract_create_state_transition: DriveAbciStateTransitionValidationVersion {
basic_structure: Some(0),
advanced_structure: None,
identity_signatures: None,
advanced_minimum_balance_pre_check: None,
nonce: Some(0),
state: 0,
transform_into_action: 0,
},
contract_update_state_transition: DriveAbciStateTransitionValidationVersion {
basic_structure: None,
advanced_structure: None,
identity_signatures: None,
advanced_minimum_balance_pre_check: None,
nonce: Some(0),
state: 0,
transform_into_action: 0,
},
documents_batch_state_transition: DriveAbciDocumentsStateTransitionValidationVersions {
balance_pre_check: 0,
basic_structure: 0,
advanced_structure: 0,
state: 0,
revision: 0,
transform_into_action: 0,
data_triggers: DriveAbciValidationDataTriggerAndBindingVersions {
bindings: 0,
triggers: DriveAbciValidationDataTriggerVersions {
create_contact_request_data_trigger: 0,
create_domain_data_trigger: 0,
create_identity_data_trigger: 0,
create_feature_flag_data_trigger: 0,
create_masternode_reward_shares_data_trigger: 0,
delete_withdrawal_data_trigger: 0,
reject_data_trigger: 0,
},
},
is_allowed: 0,
document_create_transition_structure_validation: 0,
document_delete_transition_structure_validation: 0,
document_replace_transition_structure_validation: 0,
document_transfer_transition_structure_validation: 0,
document_purchase_transition_structure_validation: 0,
document_update_price_transition_structure_validation: 0,
document_create_transition_state_validation: 1,
document_delete_transition_state_validation: 0,
document_replace_transition_state_validation: 0,
document_transfer_transition_state_validation: 0,
document_purchase_transition_state_validation: 0,
document_update_price_transition_state_validation: 0,
},
},
has_nonce_validation: 1,
process_state_transition: 0,
state_transition_to_execution_event_for_check_tx: 0,
penalties: PenaltyAmounts {
identity_id_not_correct: 50000000,
unique_key_already_present: 10000000,
validation_of_added_keys_structure_failure: 10000000,
validation_of_added_keys_proof_of_possession_failure: 50000000,
},
event_constants: DriveAbciValidationConstants {
maximum_vote_polls_to_process: 2,
maximum_contenders_to_consider: 100,
},
};
7 changes: 3 additions & 4 deletions packages/rs-platform-version/src/version/v7.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ 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_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_validation_versions::v5::DRIVE_ABCI_VALIDATION_VERSIONS_V5;
use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v2::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2;
use crate::version::drive_abci_versions::DriveAbciVersion;
use crate::version::drive_versions::v2::DRIVE_VERSION_V2;
Expand All @@ -28,15 +28,14 @@ use crate::version::ProtocolVersion;

pub const PROTOCOL_VERSION_7: ProtocolVersion = 7;

/// This version adds token support.
//todo: make changes
/// This version fixes masternode voting nonce issue.
pub const PLATFORM_V7: PlatformVersion = PlatformVersion {
protocol_version: PROTOCOL_VERSION_7,
drive: DRIVE_VERSION_V2,
drive_abci: DriveAbciVersion {
structs: DRIVE_ABCI_STRUCTURE_VERSIONS_V1,
methods: DRIVE_ABCI_METHOD_VERSIONS_V4,
validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V4,
validation_and_processing: DRIVE_ABCI_VALIDATION_VERSIONS_V5, // <--- changed to V5
withdrawal_constants: DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V2,
query: DRIVE_ABCI_QUERY_VERSIONS_V1,
},
Expand Down
Loading