Skip to content
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 @@ -290,6 +290,89 @@ mod tests {
.collect()
}

#[test]
fn should_require_the_exact_contested_dpns_fee_for_each_protocol_version() {
for (protocol_version, expected_amount) in [(13, 20_000_000_000), (14, 10_000_000_000)] {
let platform_version = PlatformVersion::get(protocol_version).expect("known version");
for paid_amount in [
9_999_999_999,
10_000_000_000,
10_000_000_001,
20_000_000_000,
20_000_000_001,
] {
let mut action = create_action(
CONTESTED_LABEL,
Some(CONTESTED_INDEX_NAME),
platform_version,
);
let DocumentCreateTransitionAction::V0(action_data) = &mut action;
action_data
.prefunded_voting_balance
.as_mut()
.expect("prefunded contest")
.1 = paid_amount;

let errors = validate(&action, platform_version);
let contest_errors = contest_errors(&errors);
if paid_amount == expected_amount {
assert!(
contest_errors.is_empty(),
"protocol {protocol_version}: {errors:?}"
);
} else {
let [StateError::DocumentContestNotPaidForError(error)] =
contest_errors.as_slice()
else {
panic!("protocol {protocol_version}: expected a fee error, got {errors:?}");
};
assert_eq!(error.expected_amount(), expected_amount);
assert_eq!(error.paid_amount(), paid_amount);
}
}
}
}

#[test]
fn should_construct_dpns_transitions_with_the_protocol_contested_fee() {
use dpp::document::{Document, DocumentV0};
use dpp::state_transition::batch_transition::document_create_transition::DocumentCreateTransition;

for (protocol_version, expected_amount) in [(13, 20_000_000_000), (14, 10_000_000_000)] {
let platform_version = PlatformVersion::get(protocol_version).expect("known version");
let contract = DataContractFetchInfo::dpns_contract_fixture(protocol_version);
let document_type = contract
.contract
.document_type_for_name("domain")
.expect("domain type");

for label in [CONTESTED_LABEL, NON_CONTESTED_LABEL] {
let document = Document::V0(DocumentV0 {
id: Identifier::from([0xAA; 32]),
owner_id: Identifier::from([0xBB; 32]),
properties: domain_properties(label),
..Default::default()
});
let DocumentCreateTransition::V0(transition) =
DocumentCreateTransition::from_document(
document,
document_type,
[0xCC; 32],
None,
1,
platform_version,
None,
None,
)
.expect("create transition");

let expected = (label == CONTESTED_LABEL)
.then(|| (CONTESTED_INDEX_NAME.to_string(), expected_amount));
assert_eq!(transition.prefunded_voting_balance, expected);
}
}
}

#[test]
fn should_reject_a_prefunded_voting_balance_naming_another_index() {
let platform_version = PlatformVersion::latest();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5664,6 +5664,10 @@ mod tests {
#[tokio::test]
async fn test_non_proved_prefunded_specialized_balance_request_after_many_votes() {
let platform_version = PlatformVersion::latest();
let vote_fees = &platform_version.fee_version.vote_resolution_fund_fees;
let contribution =
vote_fees.contested_document_vote_resolution_fund_required_amount;
let vote_cost = vote_fees.contested_document_single_vote_cost;
let mut platform = TestPlatformBuilder::new()
.with_latest_protocol_version()
.build_with_mock_rpc()
Expand All @@ -5688,7 +5692,7 @@ mod tests {
platform_version,
);

assert_eq!(start_balance, dash_to_credits!(0.4));
assert_eq!(start_balance, 2 * contribution);

let (_contender_3, _contender_4, _) = create_dpns_identity_name_contest(
&mut platform,
Expand All @@ -5707,7 +5711,7 @@ mod tests {
platform_version,
);

assert_eq!(start_balance_after_more_contenders, dash_to_credits!(0.8));
assert_eq!(start_balance_after_more_contenders, 4 * contribution);

for i in 0..50 {
let (pro_tx_hash, _masternode, signer, voting_key) =
Expand Down Expand Up @@ -5739,7 +5743,7 @@ mod tests {
platform_version,
);

assert_eq!(balance_after_50_votes, dash_to_credits!(0.795));
assert_eq!(balance_after_50_votes, 4 * contribution - 50 * vote_cost);

for i in 0..5 {
let (pro_tx_hash, _masternode, signer, voting_key) =
Expand Down Expand Up @@ -5771,12 +5775,16 @@ mod tests {
platform_version,
);

assert_eq!(balance_after_55_votes, dash_to_credits!(0.7945));
assert_eq!(balance_after_55_votes, 4 * contribution - 55 * vote_cost);
}

#[tokio::test]
async fn test_proved_prefunded_specialized_balance_request_after_many_votes() {
let platform_version = PlatformVersion::latest();
let vote_fees = &platform_version.fee_version.vote_resolution_fund_fees;
let contribution =
vote_fees.contested_document_vote_resolution_fund_required_amount;
let vote_cost = vote_fees.contested_document_single_vote_cost;
let mut platform = TestPlatformBuilder::new()
.with_latest_protocol_version()
.build_with_mock_rpc()
Expand All @@ -5801,7 +5809,7 @@ mod tests {
platform_version,
);

assert_eq!(start_balance, dash_to_credits!(0.4));
assert_eq!(start_balance, 2 * contribution);

let (_contender_3, _contender_4, _) = create_dpns_identity_name_contest(
&mut platform,
Expand All @@ -5820,7 +5828,7 @@ mod tests {
platform_version,
);

assert_eq!(start_balance_after_more_contenders, dash_to_credits!(0.8));
assert_eq!(start_balance_after_more_contenders, 4 * contribution);

for i in 0..50 {
let (pro_tx_hash, _masternode, signer, voting_key) =
Expand Down Expand Up @@ -5852,7 +5860,7 @@ mod tests {
platform_version,
);

assert_eq!(balance_after_50_votes, dash_to_credits!(0.795));
assert_eq!(balance_after_50_votes, 4 * contribution - 50 * vote_cost);

for i in 0..5 {
let (pro_tx_hash, _masternode, signer, voting_key) =
Expand Down Expand Up @@ -5884,7 +5892,7 @@ mod tests {
platform_version,
);

assert_eq!(balance_after_55_votes, dash_to_credits!(0.7945));
assert_eq!(balance_after_55_votes, 4 * contribution - 55 * vote_cost);
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/rs-platform-version/src/version/fee/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ pub mod state_transition_min_fees;
pub mod storage;
pub mod v1;
pub mod v2;
pub mod v3;
pub mod vote_resolution_fund_fees;

pub type FeeVersionNumber = u32;
Expand Down
11 changes: 11 additions & 0 deletions packages/rs-platform-version/src/version/fee/v3.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
use crate::version::fee::v2::FEE_VERSION2;
use crate::version::fee::vote_resolution_fund_fees::v2::VOTE_RESOLUTION_FUND_FEES_VERSION2;
use crate::version::fee::FeeVersion;

/// Introduced in protocol version 14 (4.2).
pub const FEE_VERSION3: FeeVersion = FeeVersion {
// Contested contributions use the active protocol, so unchanged storage
// rates retain the historical fee_version_number inherited from FEE_VERSION2.
vote_resolution_fund_fees: VOTE_RESOLUTION_FUND_FEES_VERSION2,
..FEE_VERSION2
Comment on lines +5 to +10

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: Document the deliberate mismatch between FEE_VERSION3 and fee-version lookup identity

FEE_VERSION3 inherits fee_version_number: 1, while FeeVersion::as_static() resolves that number through FEE_VERSIONS and therefore returns FEE_VERSION1. FEE_VERSION3 now differs from FEE_VERSION1 in the contested-document contribution, so a future caller that uses as_static() to recover the active fee schedule can silently obtain the old 20-billion-credit value. The inherited number is intentional for the existing storage-refund persistence scheme, but the new fee field makes the hazard materially more visible. Add an explicit warning at the constant or otherwise make the lookup API unable to present FEE_VERSION1 as FEE_VERSION3.

Suggested change
/// Introduced in protocol version 14 (4.2).
pub const FEE_VERSION3: FeeVersion = FeeVersion {
// Contested contributions use the active protocol, so unchanged storage
// rates retain the historical fee_version_number inherited from FEE_VERSION2.
vote_resolution_fund_fees: VOTE_RESOLUTION_FUND_FEES_VERSION2,
..FEE_VERSION2
/// Introduced in protocol version 14 (4.2).
///
/// `fee_version_number` intentionally remains 1 for compatibility with the
/// persisted storage-fee history. Do not use `FeeVersion::as_static()` to
/// recover this complete fee schedule: that lookup resolves number 1 to
/// `FEE_VERSION1`, not this protocol-14 configuration.
pub const FEE_VERSION3: FeeVersion = FeeVersion {

source: ['codex']

};
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use bincode::{Decode, Encode};

pub mod v1;
pub mod v2;
#[derive(Clone, Debug, Encode, Decode, Default, PartialEq, Eq)]
pub struct VoteResolutionFundFees {
/// This is the amount that will be deducted from an identity and used to pay for voting
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use crate::version::fee::vote_resolution_fund_fees::v1::VOTE_RESOLUTION_FUND_FEES_VERSION1;
use crate::version::fee::vote_resolution_fund_fees::VoteResolutionFundFees;

/// Introduced in protocol version 14 (4.2).
pub const VOTE_RESOLUTION_FUND_FEES_VERSION2: VoteResolutionFundFees = VoteResolutionFundFees {
contested_document_vote_resolution_fund_required_amount: 10_000_000_000, // 0.1 DASH
..VOTE_RESOLUTION_FUND_FEES_VERSION1
};
25 changes: 23 additions & 2 deletions packages/rs-platform-version/src/version/v14.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::version::drive_abci_versions::drive_abci_validation_versions::v10::DR
use crate::version::drive_abci_versions::drive_abci_withdrawal_constants::v3::DRIVE_ABCI_WITHDRAWAL_CONSTANTS_V3;
use crate::version::drive_abci_versions::DriveAbciVersion;
use crate::version::drive_versions::v9::DRIVE_VERSION_V9;
use crate::version::fee::v2::FEE_VERSION2;
use crate::version::fee::v3::FEE_VERSION3;
use crate::version::protocol_version::PlatformVersion;
use crate::version::system_data_contract_versions::v3::SYSTEM_DATA_CONTRACT_VERSIONS_V3;
use crate::version::system_limits::v4::SYSTEM_LIMITS_V4;
Expand Down Expand Up @@ -222,7 +222,7 @@ pub const PLATFORM_V14: PlatformVersion = PlatformVersion {
factory_versions: DPP_FACTORY_VERSIONS_V1,
},
system_data_contracts: SYSTEM_DATA_CONTRACT_VERSIONS_V3, // changed: DashPay v2 adds profile payment address fields (DIP-33)
fee_version: FEE_VERSION2,
fee_version: FEE_VERSION3, // changed: contested document contribution reduced to 0.1 DASH
system_limits: SYSTEM_LIMITS_V4, // changed: daily withdrawal limit becomes 15% of the total credits a day ago + time-range overlap-factor cap (24)
consensus: ConsensusVersions {
tenderdash_consensus_version: 1,
Expand All @@ -234,6 +234,27 @@ mod tests {
use super::*;
use crate::version::v13::PLATFORM_V13;

#[test]
fn should_halve_only_the_contested_document_fee_at_protocol_14() {
for protocol_version in 1..14 {
let version = PlatformVersion::get(protocol_version).expect("known protocol version");
assert_eq!(
version
.fee_version
.vote_resolution_fund_fees
.contested_document_vote_resolution_fund_required_amount,
20_000_000_000,
"protocol {protocol_version} must preserve the 0.2 DASH contribution"
);
}

let mut expected_fees = PLATFORM_V13.fee_version.clone();
expected_fees
.vote_resolution_fund_fees
.contested_document_vote_resolution_fund_required_amount = 10_000_000_000;
assert_eq!(PLATFORM_V14.fee_version, expected_fees);
}

/// The ranked / boolean-HAVING routing gate lives in v14's own query
/// table, so flipping it touches only v14: a v13 node keeps running
/// the v0 helper, which rejects every non-empty HAVING, so a
Expand Down
Loading