Skip to content

Commit

Permalink
feat(platform)!: distribute prefunded specialized balances after vote (
Browse files Browse the repository at this point in the history
…#2422)

Co-authored-by: Ivan Shumkov <[email protected]>
  • Loading branch information
QuantumExplorer and shumkov authored Jan 15, 2025
1 parent 94dcbb2 commit c6feb5b
Show file tree
Hide file tree
Showing 38 changed files with 2,163 additions and 42 deletions.
Original file line number Diff line number Diff line change
@@ -1,21 +1,34 @@
use crate::error::execution::ExecutionError;
use crate::error::Error;
use crate::platform_types::platform::Platform;
use crate::platform_types::platform_state::v0::PlatformStateV0Methods;
use crate::platform_types::platform_state::PlatformState;
use dpp::block::block_info::BlockInfo;
use dpp::dashcore::hashes::Hash;
use dpp::data_contracts::SystemDataContract;
use dpp::fee::Credits;
use dpp::platform_value::Identifier;
use dpp::serialization::PlatformDeserializable;
use dpp::system_data_contracts::load_system_data_contract;
use dpp::version::PlatformVersion;
use dpp::version::ProtocolVersion;
use dpp::voting::vote_polls::VotePoll;
use drive::drive::identity::key::fetch::{
IdentityKeysRequest, KeyIDIdentityPublicKeyPairBTreeMap, KeyRequestType,
};
use drive::drive::identity::withdrawals::paths::{
get_withdrawal_root_path, WITHDRAWAL_TRANSACTIONS_BROADCASTED_KEY,
WITHDRAWAL_TRANSACTIONS_SUM_AMOUNT_TREE_KEY,
};
use drive::grovedb::{Element, Transaction};
use drive::drive::prefunded_specialized_balances::{
prefunded_specialized_balances_for_voting_path,

Check warning on line 24 in packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs

View workflow job for this annotation

GitHub Actions / Rust packages (drive-abci) / Linting

unused import: `prefunded_specialized_balances_for_voting_path`

warning: unused import: `prefunded_specialized_balances_for_voting_path` --> packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs:24:5 | 24 | prefunded_specialized_balances_for_voting_path, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(unused_imports)]` on by default
prefunded_specialized_balances_for_voting_path_vec,
};
use drive::drive::votes::paths::vote_end_date_queries_tree_path_vec;
use drive::grovedb::{Element, PathQuery, Query, QueryItem, SizedQuery, Transaction};
use drive::query::QueryResultType;
use std::collections::HashSet;
use std::ops::RangeFull;

impl<C> Platform<C> {
/// Executes protocol-specific events on the first block after a protocol version change.
Expand Down Expand Up @@ -58,6 +71,20 @@ impl<C> Platform<C> {
self.transition_to_version_6(block_info, transaction, platform_version)?;
}

if previous_protocol_version < 8 && platform_version.protocol_version >= 8 {
self.transition_to_version_8(block_info, transaction, platform_version)
.or_else(|e| {
tracing::error!(
error = ?e,
"Error while transitioning to version 8: {e}"
);

// We ignore this transition errors because it's not changing the state stucture
// and not critical for the system
Ok::<(), Error>(())
})?;
}

Ok(())
}

Expand Down Expand Up @@ -86,6 +113,131 @@ impl<C> Platform<C> {
Ok(())
}

/// When transitioning to version 8 we need to empty some specialized balances
fn transition_to_version_8(
&self,
block_info: &BlockInfo,
transaction: &Transaction,
platform_version: &PlatformVersion,
) -> Result<(), Error> {

Check warning on line 122 in packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs

View workflow job for this annotation

GitHub Actions / Rust packages (drive-abci) / Linting

the `Err`-variant returned from this function is very large

warning: the `Err`-variant returned from this function is very large --> packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/perform_events_on_first_block_of_protocol_change/v0/mod.rs:122:10 | 122 | ) -> Result<(), Error> { | ^^^^^^^^^^^^^^^^^ | ::: packages/rs-drive-abci/src/error/mod.rs:28:5 | 28 | Abci(#[from] AbciError), | ----------------------- the largest variant contains at least 208 bytes | = help: try reducing the size of `error::Error`, for example by boxing large elements or replacing it with `Box<error::Error>` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#result_large_err
// Let's start by getting all the specialized balances that exist
let path_holding_specialized_balances =
prefunded_specialized_balances_for_voting_path_vec();
let path_query = PathQuery::new_single_query_item(
path_holding_specialized_balances,
QueryItem::RangeFull(RangeFull),
);
let all_specialized_balances_still_around: HashSet<_> = self
.drive
.grove_get_path_query(
&path_query,
Some(transaction),
QueryResultType::QueryKeyElementPairResultType,
&mut vec![],
&platform_version.drive,
)?
.0
.to_keys()
.into_iter()
.map(Identifier::try_from)
.collect::<Result<HashSet<_>, dpp::platform_value::Error>>()?;

let path = vote_end_date_queries_tree_path_vec();

let mut query = Query::new_with_direction(true);

query.insert_all();

let mut sub_query = Query::new();

sub_query.insert_all();

query.default_subquery_branch.subquery = Some(sub_query.into());

let current_votes_path_query = PathQuery {
path,
query: SizedQuery {
query,
limit: Some(30000), //Just a high number that shouldn't break the system
offset: None,
},
};

let (query_result_elements, _) = self.drive.grove_get_path_query(
&current_votes_path_query,
Some(transaction),
QueryResultType::QueryElementResultType,
&mut vec![],
&platform_version.drive,
)?;

let active_specialized_balances = query_result_elements
.to_elements()
.into_iter()
.map(|element| {
let contested_document_resource_vote_poll_bytes = element
.into_item_bytes()
.map_err(drive::error::Error::GroveDB)?;
let vote_poll =
VotePoll::deserialize_from_bytes(&contested_document_resource_vote_poll_bytes)?;
match vote_poll {
VotePoll::ContestedDocumentResourceVotePoll(contested) => {
contested.specialized_balance_id().map_err(Error::Protocol)
}
}
})
.collect::<Result<HashSet<Identifier>, Error>>()?;

// let's get the non-active ones
let non_active_specialized_balances =
all_specialized_balances_still_around.difference(&active_specialized_balances);

let mut total_credits_to_add_to_processing: Credits = 0;

let mut operations = vec![];

for specialized_balance_id in non_active_specialized_balances {
let (credits, mut empty_specialized_balance_operation) =
self.drive.empty_prefunded_specialized_balance_operations(
*specialized_balance_id,
false,
&mut None,
Some(transaction),
platform_version,
)?;
operations.append(&mut empty_specialized_balance_operation);
total_credits_to_add_to_processing = total_credits_to_add_to_processing
.checked_add(credits)
.ok_or(Error::Execution(ExecutionError::Overflow(
"Credits from specialized balances are overflowing",
)))?;
}

if total_credits_to_add_to_processing > 0 {
operations.push(
self.drive
.add_epoch_processing_credits_for_distribution_operation(
&block_info.epoch,
total_credits_to_add_to_processing,
Some(transaction),
platform_version,
)?,
);
}

if !operations.is_empty() {
self.drive.apply_batch_low_level_drive_operations(
None,
Some(transaction),
operations,
&mut vec![],
&platform_version.drive,
)?;
}

Ok(())
}

/// Initializes an empty sum tree for withdrawal transactions required for protocol version 4.
///
/// This function is called during the transition to protocol version 4 to set up
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ where
// This means removing it and also removing all current votes
if !vote_polls_with_info.is_empty() {
self.clean_up_after_vote_polls_end(
block_info,
&vote_polls_with_info,
clean_up_testnet_corrupted_reference_issue,
transaction,
Expand Down
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::platform_types::platform::Platform;
use crate::rpc::core::CoreRPCLike;
use dpp::block::block_info::BlockInfo;
use dpp::identifier::Identifier;
use dpp::prelude::TimestampMillis;
use dpp::version::PlatformVersion;
Expand All @@ -11,6 +12,7 @@ use drive::grovedb::TransactionArg;
use std::collections::BTreeMap;

mod v0;
mod v1;

impl<C> Platform<C>
where
Expand All @@ -19,6 +21,7 @@ where
/// Checks for ended vote polls
pub(in crate::execution) fn clean_up_after_contested_resources_vote_polls_end(
&self,
block_info: &BlockInfo,
vote_polls: Vec<(
&ContestedDocumentResourceVotePollWithContractInfo,
&TimestampMillis,
Expand All @@ -40,9 +43,16 @@ where
transaction,
platform_version,
),
1 => self.clean_up_after_contested_resources_vote_polls_end_v1(
block_info,
vote_polls,
clean_up_testnet_corrupted_reference_issue,
transaction,
platform_version,
),
version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch {
method: "clean_up_after_contested_resources_vote_polls_end".to_string(),
known_versions: vec![0],
known_versions: vec![0, 1],
received: version,
})),
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use dpp::version::PlatformVersion;
use dpp::voting::vote_choices::resource_vote_choice::ResourceVoteChoice;
use dpp::ProtocolError;
use drive::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfo;
use drive::fees::op::LowLevelDriveOperation;
use drive::grovedb::TransactionArg;
use std::collections::BTreeMap;

Expand All @@ -28,12 +29,43 @@ where
transaction: TransactionArg,
platform_version: &PlatformVersion,
) -> Result<(), Error> {
let operations = self.clean_up_after_contested_resources_vote_polls_end_operations_v0(
vote_polls.as_slice(),
clean_up_testnet_corrupted_reference_issue,
transaction,
platform_version,
)?;
if !operations.is_empty() {
self.drive.apply_batch_low_level_drive_operations(
None,
transaction,
operations,
&mut vec![],
&platform_version.drive,
)?;
}

Ok(())
}
/// Checks for ended vote polls
#[inline(always)]
pub(super) fn clean_up_after_contested_resources_vote_polls_end_operations_v0(
&self,
vote_polls: &[(
&ContestedDocumentResourceVotePollWithContractInfo,
&TimestampMillis,
&BTreeMap<ResourceVoteChoice, Vec<Identifier>>,
)],
clean_up_testnet_corrupted_reference_issue: bool,
transaction: TransactionArg,
platform_version: &PlatformVersion,
) -> Result<Vec<LowLevelDriveOperation>, Error> {
let mut operations = vec![];

// We remove the end date query
self.drive
.remove_contested_resource_vote_poll_end_date_query_operations(
vote_polls.as_slice(),
vote_polls,
&mut operations,
transaction,
platform_version,
Expand All @@ -42,7 +74,7 @@ where
// We remove the votes from under the contenders votes received
self.drive
.remove_contested_resource_vote_poll_votes_operations(
vote_polls.as_slice(),
vote_polls,
true,
&mut operations,
transaction,
Expand All @@ -52,7 +84,7 @@ where
// We remove the documents that contenders have
self.drive
.remove_contested_resource_vote_poll_documents_operations(
vote_polls.as_slice(),
vote_polls,
clean_up_testnet_corrupted_reference_issue,
&mut operations,
transaction,
Expand All @@ -62,7 +94,7 @@ where
// We remove the contenders
self.drive
.remove_contested_resource_vote_poll_contenders_operations(
vote_polls.as_slice(),
vote_polls,
&mut operations,
transaction,
platform_version,
Expand All @@ -81,7 +113,7 @@ where

let mut identity_to_vote_ids_map: BTreeMap<&Identifier, Vec<&Identifier>> = BTreeMap::new();

for (vote_poll, _, voters_for_contender) in &vote_polls {
for (vote_poll, _, voters_for_contender) in vote_polls {
let vote_id = vote_poll_ids
.iter()
.find_map(|(vp, vid)| if vp == vote_poll { Some(vid) } else { None })
Expand Down Expand Up @@ -113,31 +145,21 @@ where

if clean_up_testnet_corrupted_reference_issue {
self.drive.remove_contested_resource_info_operations(
vote_polls.as_slice(),
vote_polls,
&mut operations,
transaction,
platform_version,
)?;
// We remove the last index
self.drive
.remove_contested_resource_top_level_index_operations(
vote_polls.as_slice(),
vote_polls,
&mut operations,
transaction,
platform_version,
)?;
}

if !operations.is_empty() {
self.drive.apply_batch_low_level_drive_operations(
None,
transaction,
operations,
&mut vec![],
&platform_version.drive,
)?;
}

Ok(())
Ok(operations)
}
}
Loading

0 comments on commit c6feb5b

Please sign in to comment.