use crate::blueprints::component::*;
use crate::blueprints::resource::*;
use crate::*;
use radix_engine_common::data::manifest::model::ManifestAddressReservation;
use radix_engine_common::prelude::ManifestBucket;
use radix_engine_common::prelude::CONSENSUS_MANAGER_PACKAGE;
use radix_engine_common::time::{Instant, TimeComparisonOperator};
use radix_engine_common::types::*;
use radix_engine_interface::crypto::Secp256k1PublicKey;
use radix_engine_interface::math::{traits::*, Decimal};
use sbor::rust::fmt::Debug;
use sbor::rust::string::String;
use sbor::rust::vec::Vec;
pub const CONSENSUS_MANAGER_BLUEPRINT: &str = "ConsensusManager";
pub const VALIDATOR_BLUEPRINT: &str = "Validator";
define_type_info_marker!(Some(CONSENSUS_MANAGER_PACKAGE), ConsensusManager);
define_type_info_marker!(Some(CONSENSUS_MANAGER_PACKAGE), Validator);
pub const CONSENSUS_MANAGER_CREATE_IDENT: &str = "create";
#[derive(Debug, Eq, PartialEq, ScryptoSbor)]
pub struct ConsensusManagerCreateInput {
pub validator_owner_token_address: GlobalAddressReservation,
pub component_address: GlobalAddressReservation,
pub initial_epoch: Epoch,
pub initial_config: ConsensusManagerConfig,
pub initial_time_ms: i64,
pub initial_current_leader: Option<ValidatorIndex>,
}
#[derive(Debug, Eq, PartialEq, ManifestSbor)]
pub struct ConsensusManagerCreateManifestInput {
pub validator_owner_token_address: ManifestAddressReservation,
pub component_address: ManifestAddressReservation,
pub initial_epoch: Epoch,
pub initial_config: ConsensusManagerConfig,
pub initial_time_ms: i64,
pub initial_current_leader: Option<ValidatorIndex>,
}
#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor, ManifestSbor)]
pub struct ConsensusManagerConfig {
pub max_validators: u32,
pub epoch_change_condition: EpochChangeCondition,
pub num_unstake_epochs: u64,
pub total_emission_xrd_per_epoch: Decimal,
pub min_validator_reliability: Decimal,
pub num_owner_stake_units_unlock_epochs: u64,
pub num_fee_increase_delay_epochs: u64,
pub validator_creation_usd_cost: Decimal,
}
impl ConsensusManagerConfig {
pub fn with_max_validators(mut self, new_value: u32) -> Self {
self.max_validators = new_value;
self
}
pub fn with_epoch_change_condition(mut self, new_value: EpochChangeCondition) -> Self {
self.epoch_change_condition = new_value;
self
}
pub fn with_num_unstake_epochs(mut self, new_value: u64) -> Self {
self.num_unstake_epochs = new_value;
self
}
pub fn with_total_emission_xrd_per_epoch(mut self, new_value: Decimal) -> Self {
self.total_emission_xrd_per_epoch = new_value;
self
}
pub fn with_min_validator_reliability(mut self, new_value: Decimal) -> Self {
self.min_validator_reliability = new_value;
self
}
pub fn with_num_owner_stake_units_unlock_epochs(mut self, new_value: u64) -> Self {
self.num_owner_stake_units_unlock_epochs = new_value;
self
}
pub fn with_num_fee_increase_delay_epochs(mut self, new_value: u64) -> Self {
self.num_fee_increase_delay_epochs = new_value;
self
}
}
#[derive(Debug, Clone, PartialEq, Eq, Default, ScryptoSbor, ManifestSbor)]
pub struct EpochChangeCondition {
pub min_round_count: u64,
pub max_round_count: u64,
pub target_duration_millis: u64,
}
pub enum EpochChangeOutcome {
NoChange,
Change {
next_epoch_effective_start_millis: i64,
},
}
impl EpochChangeCondition {
pub fn should_epoch_change(
&self,
effective_start: i64,
current_time: i64,
round: Round,
) -> EpochChangeOutcome {
let epoch_duration_millis =
if current_time >= 0 && effective_start >= 0 && current_time > effective_start {
(current_time - effective_start) as u64
} else {
0
};
if self.is_change_criterion_met(epoch_duration_millis, round) {
let next_epoch_effective_start_millis =
if self.is_actual_duration_close_to_target(epoch_duration_millis) {
effective_start.saturating_add_unsigned(self.target_duration_millis)
} else {
current_time
};
EpochChangeOutcome::Change {
next_epoch_effective_start_millis,
}
} else {
EpochChangeOutcome::NoChange
}
}
fn is_actual_duration_close_to_target(&self, actual_duration_millis: u64) -> bool {
let bounds_are_compatible_with_calculation =
actual_duration_millis >= 1000 && self.target_duration_millis >= 1000;
if !bounds_are_compatible_with_calculation {
return false;
}
let proportion_difference = (Decimal::from(actual_duration_millis)
.checked_sub(self.target_duration_millis)
.expect("Overflow"))
.checked_div(self.target_duration_millis)
.expect("Overflow");
proportion_difference <= dec!("0.1")
}
fn is_change_criterion_met(&self, duration_millis: u64, round: Round) -> bool {
if round.number() >= self.max_round_count {
true
} else if round.number() < self.min_round_count {
false
} else {
duration_millis >= self.target_duration_millis
}
}
}
pub type ConsensusManagerCreateOutput = ();
pub const CONSENSUS_MANAGER_GET_CURRENT_EPOCH_IDENT: &str = "get_current_epoch";
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
pub struct ConsensusManagerGetCurrentEpochInput;
pub type ConsensusManagerGetCurrentEpochOutput = Epoch;
pub const CONSENSUS_MANAGER_START_IDENT: &str = "start";
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
pub struct ConsensusManagerStartInput {}
pub type ConsensusManagerStartOutput = ();
#[derive(Copy, Clone, Debug, Eq, PartialEq, Sbor)]
#[sbor(type_name = "TimePrecision")]
pub enum TimePrecisionV1 {
Minute,
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, Sbor)]
#[sbor(type_name = "TimePrecision")]
pub enum TimePrecisionV2 {
Minute,
Second,
}
pub type TimePrecision = TimePrecisionV2;
pub const CONSENSUS_MANAGER_GET_CURRENT_TIME_IDENT: &str = "get_current_time";
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
#[sbor(type_name = "ConsensusManagerGetCurrentTimeInput")]
pub struct ConsensusManagerGetCurrentTimeInputV1 {
pub precision: TimePrecisionV1,
}
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
#[sbor(type_name = "ConsensusManagerGetCurrentTimeInput")]
pub struct ConsensusManagerGetCurrentTimeInputV2 {
pub precision: TimePrecisionV2,
}
pub type ConsensusManagerGetCurrentTimeOutput = Instant;
pub const CONSENSUS_MANAGER_COMPARE_CURRENT_TIME_IDENT: &str = "compare_current_time";
#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
#[sbor(type_name = "ConsensusManagerCompareCurrentTimeInput")]
pub struct ConsensusManagerCompareCurrentTimeInputV1 {
pub instant: Instant,
pub precision: TimePrecisionV1,
pub operator: TimeComparisonOperator,
}
#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor)]
#[sbor(type_name = "ConsensusManagerCompareCurrentTimeInput")]
pub struct ConsensusManagerCompareCurrentTimeInputV2 {
pub instant: Instant,
pub precision: TimePrecisionV2,
pub operator: TimeComparisonOperator,
}
pub type ConsensusManagerCompareCurrentTimeOutput = bool;
pub const CONSENSUS_MANAGER_NEXT_ROUND_IDENT: &str = "next_round";
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
pub struct ConsensusManagerNextRoundInput {
pub round: Round,
pub proposer_timestamp_ms: i64,
pub leader_proposal_history: LeaderProposalHistory,
}
impl ConsensusManagerNextRoundInput {
pub fn successful(
current_round: Round,
current_leader: ValidatorIndex,
current_timestamp_ms: i64,
) -> Self {
Self {
round: current_round,
proposer_timestamp_ms: current_timestamp_ms,
leader_proposal_history: LeaderProposalHistory {
gap_round_leaders: Vec::new(),
current_leader,
is_fallback: false,
},
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
pub struct LeaderProposalHistory {
pub gap_round_leaders: Vec<ValidatorIndex>,
pub current_leader: ValidatorIndex,
pub is_fallback: bool,
}
pub type ConsensusManagerNextRoundOutput = ();
pub const CONSENSUS_MANAGER_CREATE_VALIDATOR_IDENT: &str = "create_validator";
#[derive(Debug, Eq, PartialEq, ScryptoSbor)]
pub struct ConsensusManagerCreateValidatorInput {
pub key: Secp256k1PublicKey,
pub fee_factor: Decimal,
pub xrd_payment: Bucket,
}
#[derive(Debug, Eq, PartialEq, ManifestSbor)]
pub struct ConsensusManagerCreateValidatorManifestInput {
pub key: Secp256k1PublicKey,
pub fee_factor: Decimal,
pub xrd_payment: ManifestBucket,
}
pub type ConsensusManagerCreateValidatorOutput = (Global<ValidatorObjectTypeInfo>, Bucket, Bucket);
pub const VALIDATOR_REGISTER_IDENT: &str = "register";
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
pub struct ValidatorRegisterInput {}
pub type ValidatorRegisterOutput = ();
pub const VALIDATOR_UNREGISTER_IDENT: &str = "unregister";
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
pub struct ValidatorUnregisterInput {}
pub type ValidatorUnregisterOutput = ();
pub const VALIDATOR_STAKE_AS_OWNER_IDENT: &str = "stake_as_owner";
#[derive(Debug, Eq, PartialEq, ScryptoSbor)]
pub struct ValidatorStakeAsOwnerInput {
pub stake: Bucket,
}
#[derive(Debug, Eq, PartialEq, ManifestSbor)]
pub struct ValidatorStakeAsOwnerManifestInput {
pub stake: ManifestBucket,
}
pub type ValidatorStakeAsOwnerOutput = Bucket;
pub const VALIDATOR_STAKE_IDENT: &str = "stake";
#[derive(Debug, Eq, PartialEq, ScryptoSbor)]
pub struct ValidatorStakeInput {
pub stake: Bucket,
}
#[derive(Debug, Eq, PartialEq, ManifestSbor)]
pub struct ValidatorStakeManifestInput {
pub stake: ManifestBucket,
}
pub type ValidatorStakeOutput = Bucket;
pub const VALIDATOR_UNSTAKE_IDENT: &str = "unstake";
#[derive(Debug, Eq, PartialEq, ScryptoSbor)]
pub struct ValidatorUnstakeInput {
pub stake_unit_bucket: Bucket,
}
#[derive(Debug, Eq, PartialEq, ManifestSbor)]
pub struct ValidatorUnstakeManifestInput {
pub stake_unit_bucket: ManifestBucket,
}
pub type ValidatorUnstakeOutput = Bucket;
pub const VALIDATOR_CLAIM_XRD_IDENT: &str = "claim_xrd";
#[derive(Debug, Eq, PartialEq, ScryptoSbor)]
pub struct ValidatorClaimXrdInput {
pub bucket: Bucket,
}
#[derive(Debug, Eq, PartialEq, ManifestSbor)]
pub struct ValidatorClaimXrdManifestInput {
pub bucket: ManifestBucket,
}
pub type ValidatorClaimXrdOutput = Bucket;
pub const VALIDATOR_UPDATE_KEY_IDENT: &str = "update_key";
#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor, ManifestSbor)]
pub struct ValidatorUpdateKeyInput {
pub key: Secp256k1PublicKey,
}
pub type ValidatorUpdateKeyOutput = ();
pub const VALIDATOR_UPDATE_FEE_IDENT: &str = "update_fee";
#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor, ManifestSbor)]
pub struct ValidatorUpdateFeeInput {
pub new_fee_factor: Decimal,
}
pub type ValidatorUpdateFeeOutput = ();
pub const VALIDATOR_UPDATE_ACCEPT_DELEGATED_STAKE_IDENT: &str = "update_accept_delegated_stake";
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
pub struct ValidatorUpdateAcceptDelegatedStakeInput {
pub accept_delegated_stake: bool,
}
pub type ValidatorUpdateAcceptDelegatedStakeOutput = ();
pub const VALIDATOR_ACCEPTS_DELEGATED_STAKE_IDENT: &str = "accepts_delegated_stake";
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
pub struct ValidatorAcceptsDelegatedStakeInput {}
pub type ValidatorAcceptsDelegatedStakeOutput = bool;
pub const VALIDATOR_TOTAL_STAKE_XRD_AMOUNT_IDENT: &str = "total_stake_xrd_amount";
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
pub struct ValidatorTotalStakeXrdAmountInput {}
pub type ValidatorTotalStakeXrdAmountOutput = Decimal;
pub const VALIDATOR_TOTAL_STAKE_UNIT_SUPPLY_IDENT: &str = "total_stake_unit_supply";
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
pub struct ValidatorTotalStakeUnitSupplyInput {}
pub type ValidatorTotalStakeUnitSupplyOutput = Decimal;
pub const VALIDATOR_GET_REDEMPTION_VALUE_IDENT: &str = "get_redemption_value";
#[derive(Debug, Clone, Eq, PartialEq, ScryptoSbor, ManifestSbor)]
pub struct ValidatorGetRedemptionValueInput {
pub amount_of_stake_units: Decimal,
}
pub type ValidatorGetRedemptionValueOutput = Decimal;
pub const VALIDATOR_SIGNAL_PROTOCOL_UPDATE_READINESS: &str = "signal_protocol_update_readiness";
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
pub struct ValidatorSignalProtocolUpdateReadinessInput {
pub vote: String,
}
pub type ValidatorSignalProtocolUpdateReadinessOutput = ();
pub const VALIDATOR_GET_PROTOCOL_UPDATE_READINESS_IDENT: &str = "get_protocol_update_readiness";
#[derive(Debug, Clone, Eq, PartialEq, Sbor)]
pub struct ValidatorGetProtocolUpdateReadinessInput {}
pub type ValidatorGetProtocolUpdateReadinessOutput = Option<String>;
pub const VALIDATOR_APPLY_EMISSION_IDENT: &str = "apply_emission";
#[derive(Debug, Eq, PartialEq, ScryptoSbor)]
pub struct ValidatorApplyEmissionInput {
pub xrd_bucket: Bucket,
pub epoch: Epoch,
pub proposals_made: u64,
pub proposals_missed: u64,
}
pub type ValidatorApplyEmissionOutput = ();
pub const VALIDATOR_APPLY_REWARD_IDENT: &str = "apply_reward";
#[derive(Debug, Eq, PartialEq, ScryptoSbor)]
pub struct ValidatorApplyRewardInput {
pub xrd_bucket: Bucket,
pub epoch: Epoch,
}
pub type ValidatorApplyRewardOutput = ();
pub const VALIDATOR_LOCK_OWNER_STAKE_UNITS_IDENT: &str = "lock_owner_stake_units";
#[derive(Debug, Eq, PartialEq, ScryptoSbor)]
pub struct ValidatorLockOwnerStakeUnitsInput {
pub stake_unit_bucket: Bucket,
}
#[derive(Debug, Eq, PartialEq, ManifestSbor)]
pub struct ValidatorLockOwnerStakeUnitsManifestInput {
pub stake_unit_bucket: ManifestBucket,
}
pub type ValidatorLockOwnerStakeUnitsOutput = ();
pub const VALIDATOR_START_UNLOCK_OWNER_STAKE_UNITS_IDENT: &str = "start_unlock_owner_stake_units";
#[derive(Debug, Eq, PartialEq, ScryptoSbor, ManifestSbor)]
pub struct ValidatorStartUnlockOwnerStakeUnitsInput {
pub requested_stake_unit_amount: Decimal,
}
pub type ValidatorStartUnlockOwnerStakeUnitsOutput = ();
pub const VALIDATOR_FINISH_UNLOCK_OWNER_STAKE_UNITS_IDENT: &str = "finish_unlock_owner_stake_units";
#[derive(Debug, Eq, PartialEq, ScryptoSbor, ManifestSbor)]
pub struct ValidatorFinishUnlockOwnerStakeUnitsInput {}
pub type ValidatorFinishUnlockOwnerStakeUnitsOutput = Bucket;