diff --git a/sdk/src/types/block/output/delegation.rs b/sdk/src/types/block/output/delegation.rs index c5d949a551..813a901f60 100644 --- a/sdk/src/types/block/output/delegation.rs +++ b/sdk/src/types/block/output/delegation.rs @@ -7,7 +7,6 @@ use packable::{Packable, PackableExt}; use crate::types::block::{ address::{AccountAddress, Address}, - context_input::{CommitmentContextInput, ContextInput}, output::{ chain_id::ChainId, unlock_condition::{ @@ -18,7 +17,7 @@ use crate::types::block::{ }, protocol::{ProtocolParameters, WorkScore, WorkScoreParameters}, semantic::StateTransitionError, - slot::{EpochIndex, SlotIndex}, + slot::EpochIndex, Error, }; @@ -323,12 +322,7 @@ impl DelegationOutput { } // Transition, just without full SemanticValidationContext. - pub(crate) fn transition_inner( - current_state: &Self, - next_state: &Self, - context_inputs: &[ContextInput], - protocol_parameters: &ProtocolParameters, - ) -> Result<(), StateTransitionError> { + pub(crate) fn transition_inner(current_state: &Self, next_state: &Self) -> Result<(), StateTransitionError> { #[allow(clippy::nonminimal_bool)] if !(current_state.delegation_id.is_null() && !next_state.delegation_id().is_null()) { return Err(StateTransitionError::NonDelayedClaimingTransition); @@ -341,30 +335,6 @@ impl DelegationOutput { return Err(StateTransitionError::MutatedImmutableField); } - let slot_commitment_id = context_inputs - .iter() - .find(|i| i.kind() == CommitmentContextInput::KIND) - .map(|s| s.as_commitment().slot_commitment_id()) - .ok_or(StateTransitionError::MissingCommitmentContextInput)?; - - let future_bounded_slot: SlotIndex = slot_commitment_id.slot_index() + protocol_parameters.min_committable_age; - let future_bounded_epoch = future_bounded_slot.to_epoch_index(protocol_parameters.slots_per_epoch_exponent); - - let registration_slot = future_bounded_epoch.registration_slot( - protocol_parameters.slots_per_epoch_exponent, - protocol_parameters.epoch_nearing_threshold, - ); - - let expected_end_epoch = if future_bounded_slot <= registration_slot { - future_bounded_epoch - } else { - future_bounded_epoch + 1 - }; - - if next_state.end_epoch != expected_end_epoch { - return Err(StateTransitionError::NonDelayedClaimingTransition); - } - Ok(()) } } diff --git a/sdk/src/types/block/semantic/state_transition.rs b/sdk/src/types/block/semantic/state_transition.rs index 7071cb3a38..76a86fe212 100644 --- a/sdk/src/types/block/semantic/state_transition.rs +++ b/sdk/src/types/block/semantic/state_transition.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::types::block::{ + context_input::CommitmentContextInput, output::{AccountOutput, AnchorOutput, ChainId, DelegationOutput, FoundryOutput, NftOutput, Output, TokenScheme}, payload::signed_transaction::TransactionCapabilityFlag, semantic::{SemanticValidationContext, TransactionFailureReason}, @@ -316,12 +317,36 @@ impl StateTransitionVerifier for DelegationOutput { next_state: &Self, context: &SemanticValidationContext<'_>, ) -> Result<(), StateTransitionError> { - Self::transition_inner( - current_state, - next_state, - context.transaction.context_inputs(), - &context.protocol_parameters, - ) + let protocol_parameters = &context.protocol_parameters; + + let slot_commitment_id = context + .transaction + .context_inputs() + .iter() + .find(|i| i.kind() == CommitmentContextInput::KIND) + .map(|s| s.as_commitment().slot_commitment_id()) + .ok_or(StateTransitionError::MissingCommitmentContextInput)?; + + let future_bounded_slot_index = slot_commitment_id.slot_index() + protocol_parameters.min_committable_age; + let future_bounded_epoch_index = + future_bounded_slot_index.to_epoch_index(protocol_parameters.slots_per_epoch_exponent); + + let registration_slot = future_bounded_epoch_index.registration_slot( + protocol_parameters.slots_per_epoch_exponent, + protocol_parameters.epoch_nearing_threshold, + ); + + let expected_end_epoch = if future_bounded_slot_index <= registration_slot { + future_bounded_epoch_index + } else { + future_bounded_epoch_index + 1 + }; + + if next_state.end_epoch() != expected_end_epoch { + return Err(StateTransitionError::NonDelayedClaimingTransition); + } + + Self::transition_inner(current_state, next_state) } fn destruction( diff --git a/sdk/src/types/block/slot/epoch.rs b/sdk/src/types/block/slot/epoch.rs index deefc45b2a..bfd2d273ef 100644 --- a/sdk/src/types/block/slot/epoch.rs +++ b/sdk/src/types/block/slot/epoch.rs @@ -83,10 +83,7 @@ impl EpochIndex { /// Returns the slot at which delegation can happen for the following epoch. pub fn registration_slot(&self, slots_per_epoch_exponent: u8, epoch_nearing_threshold: u32) -> SlotIndex { - self.first_slot_index(slots_per_epoch_exponent) - - epoch_nearing_threshold - - self.activity_window_slot(slots_per_epoch_exponent, epoch_nearing_threshold) - - 1 + self.last_slot_index(slots_per_epoch_exponent) - epoch_nearing_threshold } }