Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 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
2 changes: 1 addition & 1 deletion packages/rs-dpp/src/data_contract/config/v0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ pub trait DataContractConfigSettersV0 {
);
}

impl std::default::Default for DataContractConfigV0 {
impl Default for DataContractConfigV0 {
fn default() -> Self {
DataContractConfigV0 {
can_be_deleted: DEFAULT_CONTRACT_CAN_BE_DELETED,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -531,9 +531,10 @@ impl DocumentPropertyType {
} else {
let mut value: Vec<u8> = vec![0u8; bytes];
buf.read_exact(&mut value).map_err(|_| {
DataContractError::CorruptedSerialization(
"error reading varint from serialized document".to_string(),
)
DataContractError::CorruptedSerialization(format!(
"error reading varint of length {} from serialized document",
bytes
))
})?;
Ok(value)
}
Expand Down
1 change: 0 additions & 1 deletion packages/rs-dpp/src/data_contract/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,6 @@ mod tests {
let platform_version = PlatformVersion::latest();
let data_contract = load_system_data_contract(Dashpay, platform_version)
.expect("expected dashpay contract");
let platform_version = PlatformVersion::latest();
let serialized = data_contract
.serialize_to_bytes_with_platform_version(platform_version)
.expect("expected to serialize data contract");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::data_contract::config::v0::DataContractConfigV0;
use crate::data_contract::config::v1::DataContractConfigV1;
use crate::data_contract::config::DataContractConfig;
use crate::data_contract::document_type::accessors::DocumentTypeV0Getters;

Expand Down Expand Up @@ -26,7 +26,7 @@ pub struct DataContractInSerializationFormatV1 {
pub id: Identifier,

/// Internal configuration for the contract.
#[serde(default = "DataContractConfigV0::default_with_version")]
#[serde(default = "DataContractConfigV1::default_with_version")]
pub config: DataContractConfig,

/// The version of this data contract.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,4 +142,60 @@ mod tests {
.expect("expected to serialize consume");
}
}

#[test]
fn test_withdrawal_deserialization() {
let platform_version = PlatformVersion::latest();
let contract = json_document_to_contract(
"../rs-drive/tests/supporting_files/contract/withdrawals/withdrawals-contract.json",
false,
platform_version,
)
.expect("expected to get withdrawals contract");

// Header (65 bytes)
//
// - 01 - Document Version (1 byte): Value = 1
// - 0053626cafc76f47062f936c5938190f5f30aac997b8fc22e81c1d9a7f903bd9 - Document ID (32 bytes)
// - fa8696d3f39c518784e53be79ee199e70387f9a7408254de920c1f3779de2856 - Owner ID (32 bytes)
//
// Metadata (19 bytes)
//
// - 01 - Revision (1 byte): Value = 1
// - 0003 - Bitwise flags (2 bytes): Binary 0000000000000011
// - Bit 0 set: createdAt present
// - Bit 1 set: updatedAt present
// - 0000019782b96d14 - createdAt timestamp (8 bytes): 1750244879636
// - 0000019782b96d14 - updatedAt timestamp (8 bytes): 1750244879636
//
// User Properties (42 bytes)
//
// - 00 - transactionIndex marker (1 byte): 0 = absent
// - 00 - transactionSignHeight marker (1 byte): 0 = absent
// - 00000002540be400 - amount (8 bytes): 10000000000 duffs (100 DASH)
// - 00000001 - coreFeePerByte (4 bytes): 1 duff/byte
// - 00 - pooling (1 byte): 0 (Never pool)
// - 19 - outputScript length (1 byte varint): 25 bytes
// - 76a9149e3292d2612122d81613fdb893dd36a04df3355588ac - outputScript data (25 bytes)
// - This is a standard Bitcoin P2PKH script:
// - 76 = OP_DUP
// - a9 = OP_HASH160
// - 14 = Push 20 bytes
// - 9e3292d2612122d81613fdb893dd36a04df33555 = recipient's pubkey hash
// - 88 = OP_EQUALVERIFY
// - ac = OP_CHECKSIG
// - 00 - status (1 byte): 0 (QUEUED)

let document_type = contract
.document_type_for_name("withdrawal")
.expect("expected to get profile document type");
let serialized_document = hex::decode("010053626cafc76f47062f936c5938190f5f30aac997b8fc22e81c1d9a7f903bd9fa8696d3f39c518784e53be79ee199e70387f9a7408254de920c1f3779de28560100030000019782b96d140000019782b96d14000000000002540be40000000001001976a9149e3292d2612122d81613fdb893dd36a04df3355588ac00").expect("expected document hex bytes");

let _deserialized_document = Document::from_bytes(
serialized_document.as_slice(),
document_type,
platform_version,
)
.expect("expected to deserialize a document");
}
}
38 changes: 36 additions & 2 deletions packages/rs-dpp/src/system_data_contracts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,43 @@ use crate::ProtocolError;
use std::collections::{BTreeMap, BTreeSet};

use crate::data_contract::accessors::v0::DataContractV0Setters;
use crate::data_contract::config::v1::DataContractConfigSettersV1;
use crate::data_contract::config::DataContractConfig;
pub use data_contracts::*;
use platform_version::version::PlatformVersion;

pub trait ConfigurationForSystemContract {
fn configuration_in_platform_version(
&self,
version: &PlatformVersion,
) -> Result<DataContractConfig, ProtocolError>;
}

impl ConfigurationForSystemContract for SystemDataContract {
fn configuration_in_platform_version(
&self,
platform_version: &PlatformVersion,
) -> Result<DataContractConfig, ProtocolError> {
match self {
SystemDataContract::Withdrawals
| SystemDataContract::MasternodeRewards
| SystemDataContract::FeatureFlags
| SystemDataContract::DPNS
| SystemDataContract::Dashpay
| SystemDataContract::WalletUtils => {
let mut config = DataContractConfig::default_for_version(platform_version)?;
config.set_sized_integer_types_enabled(false);
Ok(config)
}
SystemDataContract::TokenHistory | SystemDataContract::KeywordSearch => {
let mut config = DataContractConfig::default_for_version(platform_version)?;
config.set_sized_integer_types_enabled(true);
Ok(config)
}
}
}
}

fn create_data_contract(
factory: &DataContractFactory,
system_contract: SystemDataContract,
Expand All @@ -25,11 +59,11 @@ fn create_data_contract(
let id = Identifier::from(id_bytes);
let owner_id = Identifier::from(owner_id_bytes);

let mut data_contract = factory.create_with_value_config(
let mut data_contract = factory.create(
owner_id,
0,
document_schemas.into(),
None,
Some(system_contract.configuration_in_platform_version(platform_version)?),
definitions.map(|def| def.into()),
)?;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,60 @@ where
)?;

if documents.is_empty() {
tracing::debug!(
height = block_info.height,
withdrawal_limit = platform_version
.system_limits
.withdrawal_transactions_per_block_limit,
"No queued withdrawal documents found to pool into transactions"
);
let all_documents = self
.drive
.fetch_oldest_withdrawal_documents(transaction, platform_version)?;
if all_documents.is_empty() {
tracing::debug!(
height = block_info.height,
"No withdrawal documents found at all"
);
} else if tracing::enabled!(tracing::Level::DEBUG) {
// Count documents by status
let queued_count = all_documents
.get(&(withdrawals_contract::WithdrawalStatus::QUEUED as u8))
.map(|v| v.len())
.unwrap_or(0);
let pooled_count = all_documents
.get(&(withdrawals_contract::WithdrawalStatus::POOLED as u8))
.map(|v| v.len())
.unwrap_or(0);
let broadcasted_count = all_documents
.get(&(withdrawals_contract::WithdrawalStatus::BROADCASTED as u8))
.map(|v| v.len())
.unwrap_or(0);
let complete_count = all_documents
.get(&(withdrawals_contract::WithdrawalStatus::COMPLETE as u8))
.map(|v| v.len())
.unwrap_or(0);
let expired_count = all_documents
.get(&(withdrawals_contract::WithdrawalStatus::EXPIRED as u8))
.map(|v| v.len())
.unwrap_or(0);
let total_documents = queued_count
+ pooled_count
+ broadcasted_count
+ complete_count
+ expired_count;

tracing::debug!(
height = block_info.height,
total_documents,
queued_count,
pooled_count,
broadcasted_count,
complete_count,
expired_count,
"Found withdrawal documents grouped by status"
);
}
return Ok(());
}

Expand All @@ -50,6 +104,12 @@ where
.drive
.calculate_current_withdrawal_limit(transaction, platform_version)?;

tracing::trace!(
?withdrawals_info,
documents_count = documents.len(),
"Calculated withdrawal limit info"
);

let current_withdrawal_limit = withdrawals_info.available();

// Store prometheus metrics
Expand All @@ -75,7 +135,7 @@ where
))
})?;

// If adding this withdrawal would exceed the limit, stop processing further.
// If adding this withdrawal would exceed the limit, stop further processing.
if potential_total_withdrawal_amount > current_withdrawal_limit {
tracing::debug!(
"Pooling is limited due to daily withdrawals limit. {} credits left",
Expand All @@ -91,6 +151,10 @@ where
}

if documents_to_process.is_empty() {
tracing::debug!(
block_info = %block_info,
"No withdrawal documents to process"
);
return Ok(());
}

Expand Down
64 changes: 32 additions & 32 deletions packages/rs-drive-abci/src/query/document_query/v0/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -772,10 +772,10 @@ mod tests {
owner_id: Identifier::random_with_rng(&mut std_rng),
properties: {
let mut properties = BTreeMap::new();
properties.insert("status".to_string(), Value::U8(0)); // Always queued
properties.insert("pooling".to_string(), Value::U8(0)); // Always 0
properties.insert("coreFeePerByte".to_string(), Value::U32(1)); // Always 1
properties.insert("amount".to_string(), Value::U64(1000)); // Set a minimum amount of 1000
properties.insert("status".to_string(), Value::I64(0)); // Always queued
properties.insert("pooling".to_string(), Value::I64(0)); // Always 0
properties.insert("coreFeePerByte".to_string(), Value::I64(1)); // Always 1
properties.insert("amount".to_string(), Value::I64(1000)); // Set a minimum amount of 1000
properties.insert("outputScript".to_string(), Value::Bytes(vec![])); // Set an empty output script
properties
},
Expand Down Expand Up @@ -936,10 +936,10 @@ mod tests {
owner_id: Identifier::random_with_rng(&mut std_rng),
properties: {
let mut properties = BTreeMap::new();
properties.insert("status".to_string(), Value::U8(i as u8 % 4)); // Always queued
properties.insert("pooling".to_string(), Value::U8(0)); // Always 0
properties.insert("coreFeePerByte".to_string(), Value::U32(1)); // Always 1
properties.insert("amount".to_string(), Value::U64(1000)); // Set a minimum amount of 1000
properties.insert("status".to_string(), Value::I64(i as i64 % 4)); // Always queued
properties.insert("pooling".to_string(), Value::I64(0)); // Always 0
properties.insert("coreFeePerByte".to_string(), Value::I64(1)); // Always 1
properties.insert("amount".to_string(), Value::I64(1000)); // Set a minimum amount of 1000
properties.insert("outputScript".to_string(), Value::Bytes(vec![])); // Set an empty output script
properties
},
Expand Down Expand Up @@ -1100,10 +1100,10 @@ mod tests {
owner_id: Identifier::random_with_rng(&mut std_rng),
properties: {
let mut properties = BTreeMap::new();
properties.insert("status".to_string(), Value::U8(i as u8 % 4)); // Always queued
properties.insert("pooling".to_string(), Value::U8(0)); // Always 0
properties.insert("coreFeePerByte".to_string(), Value::U32(1)); // Always 1
properties.insert("amount".to_string(), Value::U64(1000)); // Set a minimum amount of 1000
properties.insert("status".to_string(), Value::I64(i as i64 % 4)); // Always queued
properties.insert("pooling".to_string(), Value::I64(0)); // Always 0
properties.insert("coreFeePerByte".to_string(), Value::I64(1)); // Always 1
properties.insert("amount".to_string(), Value::I64(1000)); // Set a minimum amount of 1000
properties.insert("outputScript".to_string(), Value::Bytes(vec![])); // Set an empty output script
properties
},
Expand Down Expand Up @@ -1256,10 +1256,10 @@ mod tests {
owner_id: Identifier::random_with_rng(&mut std_rng),
properties: {
let mut properties = BTreeMap::new();
properties.insert("status".to_string(), Value::U8(i as u8 % 4)); // Always queued
properties.insert("pooling".to_string(), Value::U8(0)); // Always 0
properties.insert("coreFeePerByte".to_string(), Value::U32(1)); // Always 1
properties.insert("amount".to_string(), Value::U64(1000)); // Set a minimum amount of 1000
properties.insert("status".to_string(), Value::I64(i as i64 % 4)); // Always queued
properties.insert("pooling".to_string(), Value::I64(0)); // Always 0
properties.insert("coreFeePerByte".to_string(), Value::I64(1)); // Always 1
properties.insert("amount".to_string(), Value::I64(1000)); // Set a minimum amount of 1000
properties.insert("outputScript".to_string(), Value::Bytes(vec![])); // Set an empty output script
properties
},
Expand Down Expand Up @@ -1301,11 +1301,11 @@ mod tests {
field: "status".to_string(),
operator: WhereOperator::In,
value: Value::Array(vec![
Value::U8(0),
Value::U8(1),
Value::U8(2),
Value::U8(3),
Value::U8(4),
Value::I64(0),
Value::I64(1),
Value::I64(2),
Value::I64(3),
Value::I64(4),
]),
}),
range_clause: None,
Expand Down Expand Up @@ -1427,10 +1427,10 @@ mod tests {
owner_id: Identifier::random_with_rng(&mut std_rng),
properties: {
let mut properties = BTreeMap::new();
properties.insert("status".to_string(), Value::U8(i as u8 % 4)); // Always queued
properties.insert("pooling".to_string(), Value::U8(0)); // Always 0
properties.insert("coreFeePerByte".to_string(), Value::U32(1)); // Always 1
properties.insert("amount".to_string(), Value::U64(1000)); // Set a minimum amount of 1000
properties.insert("status".to_string(), Value::I64(i as i64 % 4)); // Always queued
properties.insert("pooling".to_string(), Value::I64(0)); // Always 0
properties.insert("coreFeePerByte".to_string(), Value::I64(1)); // Always 1
properties.insert("amount".to_string(), Value::I64(1000)); // Set a minimum amount of 1000
properties.insert("outputScript".to_string(), Value::Bytes(vec![])); // Set an empty output script
properties
},
Expand Down Expand Up @@ -1472,11 +1472,11 @@ mod tests {
field: "status".to_string(),
operator: WhereOperator::In,
value: Value::Array(vec![
Value::U8(0),
Value::U8(1),
Value::U8(2),
Value::U8(3),
Value::U8(4),
Value::I64(0),
Value::I64(1),
Value::I64(2),
Value::I64(3),
Value::I64(4),
]),
}),
range_clause: None,
Expand All @@ -1486,15 +1486,15 @@ mod tests {
WhereClause {
field: "pooling".to_string(),
operator: WhereOperator::Equal,
value: Value::U8(0),
value: Value::I64(0),
},
),
(
"coreFeePerByte".to_string(),
WhereClause {
field: "coreFeePerByte".to_string(),
operator: WhereOperator::Equal,
value: Value::U32(1),
value: Value::I64(1),
},
),
]),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ pub fn generate_test_masternodes(

for (key, values) in input {
for value in values {
output.entry(value).or_insert_with(Vec::new).push(key);
output.entry(value).or_default().push(key);
}
}

Expand Down
Loading
Loading