Skip to content

Commit e11bfa5

Browse files
fix: fixed Platform State deserialization issue
1 parent 5aed75a commit e11bfa5

File tree

23 files changed

+407
-270
lines changed

23 files changed

+407
-270
lines changed

packages/rs-dpp/src/core_types/validator/v0/mod.rs

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,8 @@ impl Encode for ValidatorV0 {
4747
// Encode each field in the order they appear in the struct
4848

4949
// Encode ProTxHash
50-
self.pro_tx_hash.to_byte_array().to_vec().encode(encoder)?;
50+
let pro_tx_hash_bytes = self.pro_tx_hash.as_byte_array();
51+
pro_tx_hash_bytes.encode(encoder)?;
5152

5253
// Encode Option<BlsPublicKey>
5354
match &self.public_key {
@@ -64,7 +65,8 @@ impl Encode for ValidatorV0 {
6465
self.node_ip.encode(encoder)?;
6566

6667
// Encode node_id
67-
self.node_id.to_byte_array().to_vec().encode(encoder)?;
68+
let node_id_bytes = self.node_id.as_byte_array();
69+
node_id_bytes.encode(encoder)?;
6870

6971
// Encode core_port, platform_http_port, and platform_p2p_port as u16
7072
self.core_port.encode(encoder)?;
@@ -84,14 +86,14 @@ impl Decode for ValidatorV0 {
8486
// Decode each field in the same order as they were encoded
8587

8688
// Decode ProTxHash
87-
let pro_tx_hash_bytes = Vec::<u8>::decode(decoder)?;
89+
let pro_tx_hash_bytes = <[u8; 32]>::decode(decoder)?;
8890
let pro_tx_hash = ProTxHash::from_slice(&pro_tx_hash_bytes)
8991
.map_err(|_| DecodeError::OtherString("Failed to decode ProTxHash".to_string()))?;
9092

9193
// Decode Option<BlsPublicKey>
9294
let has_public_key = bool::decode(decoder)?;
9395
let public_key = if has_public_key {
94-
let public_key_bytes = Vec::<u8>::decode(decoder)?;
96+
let public_key_bytes = <[u8; 48]>::decode(decoder)?;
9597
Some(BlsPublicKey::from_bytes(&public_key_bytes).map_err(|_| {
9698
DecodeError::OtherString("Failed to decode BlsPublicKey".to_string())
9799
})?)
@@ -103,7 +105,7 @@ impl Decode for ValidatorV0 {
103105
let node_ip = String::decode(decoder)?;
104106

105107
// Decode node_id
106-
let node_id_bytes = Vec::<u8>::decode(decoder)?;
108+
let node_id_bytes = <[u8; 20]>::decode(decoder)?;
107109
let node_id = PubkeyHash::from_slice(&node_id_bytes)
108110
.map_err(|_| DecodeError::OtherString("Failed to decode NodeId".to_string()))?;
109111

@@ -250,3 +252,45 @@ impl ValidatorV0Setters for ValidatorV0 {
250252
self.is_banned = is_banned;
251253
}
252254
}
255+
256+
#[cfg(test)]
257+
mod tests {
258+
use super::*;
259+
use bincode::config;
260+
261+
#[test]
262+
fn test_serialize_deserialize_validator_v0() {
263+
// Sample data for testing
264+
let pro_tx_hash = ProTxHash::from_slice(&[1; 32]).unwrap();
265+
let public_key = Some(BlsPublicKey::generate());
266+
let node_ip = "127.0.0.1".to_string();
267+
let node_id = PubkeyHash::from_slice(&[3; 20]).unwrap();
268+
let core_port = 9999;
269+
let platform_http_port = 8888;
270+
let platform_p2p_port = 7777;
271+
let is_banned = false;
272+
273+
// Create a ValidatorV0 instance
274+
let validator = ValidatorV0 {
275+
pro_tx_hash,
276+
public_key,
277+
node_ip,
278+
node_id,
279+
core_port,
280+
platform_http_port,
281+
platform_p2p_port,
282+
is_banned,
283+
};
284+
285+
// Serialize the ValidatorV0 instance
286+
let encoded = bincode::encode_to_vec(&validator, config::standard()).unwrap();
287+
288+
// Deserialize the data back into a ValidatorV0 instance
289+
let decoded: ValidatorV0 = bincode::decode_from_slice(&encoded, config::standard())
290+
.unwrap()
291+
.0;
292+
293+
// Verify that the deserialized instance matches the original instance
294+
assert_eq!(validator, decoded);
295+
}
296+
}

packages/rs-dpp/src/core_types/validator_set/v0/mod.rs

Lines changed: 77 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ impl Display for ValidatorSetV0 {
7070
impl Encode for ValidatorSetV0 {
7171
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
7272
// Encode each field in the order they appear in the struct
73-
let quorum_hash_bytes = self.quorum_hash.as_byte_array().to_vec();
73+
let quorum_hash_bytes = self.quorum_hash.as_byte_array();
7474
quorum_hash_bytes.encode(encoder)?;
7575
self.quorum_index.encode(encoder)?;
7676
self.core_height.encode(encoder)?;
@@ -85,7 +85,7 @@ impl Encode for ValidatorSetV0 {
8585

8686
// Custom encoding for BlsPublicKey if needed
8787
// Assuming BlsPublicKey can be serialized to a byte slice
88-
let public_key_bytes = self.threshold_public_key.to_bytes();
88+
let public_key_bytes = *self.threshold_public_key.to_bytes();
8989
public_key_bytes.encode(encoder)?;
9090

9191
Ok(())
@@ -95,8 +95,8 @@ impl Encode for ValidatorSetV0 {
9595
#[cfg(feature = "core-types-serialization")]
9696
impl Decode for ValidatorSetV0 {
9797
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, bincode::error::DecodeError> {
98-
// Decode each field in the same order as they were encoded
99-
let quorum_hash = Vec::<u8>::decode(decoder)?;
98+
// Decode the quorum hash directly as a [u8; 32] array
99+
let quorum_hash = <[u8; 32]>::decode(decoder)?;
100100
let quorum_index = Option::<u32>::decode(decoder)?;
101101
let core_height = u32::decode(decoder)?;
102102

@@ -114,17 +114,16 @@ impl Decode for ValidatorSetV0 {
114114
})
115115
.collect::<Result<_, bincode::error::DecodeError>>()?;
116116

117-
// Custom decoding for BlsPublicKey if needed
118-
// Assuming BlsPublicKey can be deserialized from a byte slice
119-
let public_key_bytes = Vec::<u8>::decode(decoder)?;
117+
// Decode the [u8; 48] directly
118+
let mut public_key_bytes = [0u8; 48];
119+
let bytes = <[u8; 48]>::decode(decoder)?;
120+
public_key_bytes.copy_from_slice(&bytes);
120121
let threshold_public_key = BlsPublicKey::from_bytes(&public_key_bytes).map_err(|_| {
121122
bincode::error::DecodeError::OtherString("Failed to decode BlsPublicKey".to_string())
122123
})?;
123124

124125
Ok(ValidatorSetV0 {
125-
quorum_hash: QuorumHash::from_slice(&quorum_hash).map_err(|_| {
126-
bincode::error::DecodeError::OtherString("Failed to decode QuorumHash".to_string())
127-
})?,
126+
quorum_hash: QuorumHash::from_byte_array(quorum_hash),
128127
quorum_index,
129128
core_height,
130129
members,
@@ -138,8 +137,8 @@ impl<'de> BorrowDecode<'de> for ValidatorSetV0 {
138137
fn borrow_decode<D: Decoder>(decoder: &mut D) -> Result<Self, bincode::error::DecodeError> {
139138
// Decode each field in the same order as they were encoded
140139

141-
// Decode quorum_hash as Vec<u8>
142-
let quorum_hash = Vec::<u8>::decode(decoder)?;
140+
// Decode the quorum hash directly as a [u8; 32] array
141+
let quorum_hash = <[u8; 32]>::decode(decoder)?;
143142
// Decode quorum_index as Option<u32>
144143
let quorum_index = Option::<u32>::decode(decoder)?;
145144
// Decode core_height as u32
@@ -160,15 +159,17 @@ impl<'de> BorrowDecode<'de> for ValidatorSetV0 {
160159
.collect::<Result<_, bincode::error::DecodeError>>()?;
161160

162161
// Custom decoding for BlsPublicKey if needed
163-
let public_key_bytes = Vec::<u8>::decode(decoder)?;
162+
let mut public_key_bytes = [0u8; 48];
163+
let bytes = <[u8; 48]>::decode(decoder)?;
164+
public_key_bytes.copy_from_slice(&bytes);
164165
let threshold_public_key = BlsPublicKey::from_bytes(&public_key_bytes).map_err(|_| {
165-
bincode::error::DecodeError::OtherString("Failed to decode BlsPublicKey".to_string())
166+
bincode::error::DecodeError::OtherString(
167+
"Failed to decode BlsPublicKey in borrow decode".to_string(),
168+
)
166169
})?;
167170

168171
Ok(ValidatorSetV0 {
169-
quorum_hash: QuorumHash::from_slice(&quorum_hash).map_err(|_| {
170-
bincode::error::DecodeError::OtherString("Failed to decode QuorumHash".to_string())
171-
})?,
172+
quorum_hash: QuorumHash::from_byte_array(quorum_hash),
172173
quorum_index,
173174
core_height,
174175
members,
@@ -278,3 +279,62 @@ impl ValidatorSetV0Setters for ValidatorSetV0 {
278279
self.threshold_public_key = threshold_public_key;
279280
}
280281
}
282+
283+
#[cfg(test)]
284+
mod tests {
285+
use super::*;
286+
use bincode::config;
287+
use dashcore::PubkeyHash;
288+
use std::collections::BTreeMap;
289+
290+
#[test]
291+
fn test_serialize_deserialize_validator_set_v0() {
292+
// Sample data for testing
293+
let quorum_hash = QuorumHash::from_slice(&[1; 32]).unwrap();
294+
let quorum_index = Some(42);
295+
let core_height = 1000;
296+
297+
// Create a sample ProTxHash and ValidatorV0 instance
298+
let pro_tx_hash = ProTxHash::from_slice(&[2; 32]).unwrap();
299+
let public_key = Some(BlsPublicKey::generate());
300+
let node_ip = "192.168.1.1".to_string();
301+
let node_id = PubkeyHash::from_slice(&[4; 20]).unwrap();
302+
let validator = ValidatorV0 {
303+
pro_tx_hash: pro_tx_hash.clone(),
304+
public_key,
305+
node_ip,
306+
node_id,
307+
core_port: 8080,
308+
platform_http_port: 9090,
309+
platform_p2p_port: 10010,
310+
is_banned: false,
311+
};
312+
313+
// Create a BTreeMap with one entry for the ValidatorSetV0
314+
let mut members = BTreeMap::new();
315+
members.insert(pro_tx_hash, validator);
316+
317+
// Create a sample threshold public key
318+
let threshold_public_key = BlsPublicKey::generate();
319+
320+
// Create the ValidatorSetV0 instance
321+
let validator_set = ValidatorSetV0 {
322+
quorum_hash,
323+
quorum_index,
324+
core_height,
325+
members,
326+
threshold_public_key,
327+
};
328+
329+
// Serialize the ValidatorSetV0 instance
330+
let encoded = bincode::encode_to_vec(&validator_set, config::standard()).unwrap();
331+
332+
// Deserialize the data back into a ValidatorSetV0 instance
333+
let decoded: ValidatorSetV0 = bincode::decode_from_slice(&encoded, config::standard())
334+
.unwrap()
335+
.0;
336+
337+
// Verify that the deserialized instance matches the original instance
338+
assert_eq!(validator_set, decoded);
339+
}
340+
}

packages/rs-dpp/src/fee/default_costs/mod.rs

Lines changed: 23 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,26 @@
1-
// MIT LICENSE
2-
//
3-
// Copyright (c) 2021 Dash Core Group
4-
//
5-
// Permission is hereby granted, free of charge, to any
6-
// person obtaining a copy of this software and associated
7-
// documentation files (the "Software"), to deal in the
8-
// Software without restriction, including without
9-
// limitation the rights to use, copy, modify, merge,
10-
// publish, distribute, sublicense, and/or sell copies of
11-
// the Software, and to permit persons to whom the Software
12-
// is furnished to do so, subject to the following
13-
// conditions:
14-
//
15-
// The above copyright notice and this permission notice
16-
// shall be included in all copies or substantial portions
17-
// of the Software.
18-
//
19-
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
20-
// ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
21-
// TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
22-
// PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
23-
// SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
24-
// CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25-
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
26-
// IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27-
// DEALINGS IN THE SOFTWARE.
28-
//
29-
301
//! Fee costs
312
//!
323
//! Fee costs for Known Platform operations
334
//!
345
356
use crate::block::epoch::{Epoch, EpochIndex};
367
use crate::fee::Credits;
37-
use platform_version::version::fee::FeeVersion;
38-
use platform_version::version::PlatformVersion;
8+
use platform_version::version::fee::{
9+
FeeVersion, FeeVersionFieldsBeforeVersion4, FeeVersionNumber,
10+
};
3911
use std::collections::BTreeMap;
4012

4113
pub mod constants;
4214

43-
pub type CachedEpochIndexFeeVersions = BTreeMap<EpochIndex, FeeVersion>;
15+
pub type CachedEpochIndexFeeVersions = BTreeMap<EpochIndex, &'static FeeVersion>;
16+
pub type EpochIndexFeeVersionsForStorage = BTreeMap<EpochIndex, FeeVersionNumber>;
17+
18+
// This is type only meant for deserialization because of an issue
19+
// The issue was that the platform state was stored with FeeVersions in it before version 1.4
20+
// When we would add new fields we would be unable to deserialize
21+
// This FeeProcessingVersionFieldsBeforeVersion4 is how things were before version 1.4 was released
22+
pub type CachedEpochIndexFeeVersionsFieldsBeforeVersion4 =
23+
BTreeMap<EpochIndex, FeeVersionFieldsBeforeVersion4>;
4424

4525
/// A Known Cost Item is an item that changes costs depending on the Epoch
4626
#[derive(Eq, PartialEq, Copy, Clone, Hash)]
@@ -143,7 +123,10 @@ impl KnownCostItem {
143123
pub trait EpochCosts {
144124
/// Get the closest epoch in the past that has a cost table
145125
/// This is where the base costs last changed
146-
fn active_fee_version(&self, cached_fee_version: &CachedEpochIndexFeeVersions) -> FeeVersion;
126+
fn active_fee_version(
127+
&self,
128+
cached_fee_version: &CachedEpochIndexFeeVersions,
129+
) -> &'static FeeVersion;
147130
/// Get the cost for the known cost item
148131
fn cost_for_known_cost_item(
149132
&self,
@@ -154,18 +137,20 @@ pub trait EpochCosts {
154137

155138
impl EpochCosts for Epoch {
156139
/// Get the active fee version for an epoch
157-
fn active_fee_version(&self, cached_fee_version: &CachedEpochIndexFeeVersions) -> FeeVersion {
140+
fn active_fee_version(
141+
&self,
142+
cached_fee_version: &CachedEpochIndexFeeVersions,
143+
) -> &'static FeeVersion {
158144
// If the exact EpochIndex is matching to a FeeVersion update
159145
if let Some(fee_version) = cached_fee_version.get(&self.index) {
160-
return fee_version.clone();
146+
return fee_version;
161147
}
162148
// else return the FeeVersion at lower adjacent EpochIndex (if available, else the FeeVersion of first PlatformVersion)
163149
cached_fee_version
164150
.range(..=self.index)
165151
.next_back()
166-
.map(|(_, fee_version)| fee_version)
167-
.unwrap_or_else(|| &PlatformVersion::first().fee_version)
168-
.clone()
152+
.map(|(_, fee_version)| *fee_version)
153+
.unwrap_or_else(|| FeeVersion::first())
169154
}
170155

171156
/// Get the cost for the known cost item

packages/rs-dpp/src/fee/fee_result/refunds.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,10 +182,10 @@ impl IntoIterator for FeeRefunds {
182182
mod tests {
183183
use super::*;
184184
use once_cell::sync::Lazy;
185-
use platform_version::version::PlatformVersion;
185+
use platform_version::version::fee::FeeVersion;
186186

187187
static EPOCH_CHANGE_FEE_VERSION_TEST: Lazy<CachedEpochIndexFeeVersions> =
188-
Lazy::new(|| BTreeMap::from([(0, PlatformVersion::first().fee_version.clone())]));
188+
Lazy::new(|| BTreeMap::from([(0, FeeVersion::first())]));
189189

190190
mod from_storage_removal {
191191
use super::*;

packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -795,7 +795,7 @@ mod refund_tests {
795795

796796
platform_state
797797
.previous_fee_versions_mut()
798-
.insert(5, platform_version_with_higher_fees.fee_version.clone());
798+
.insert(5, platform_version_with_higher_fees.fee_version.as_static());
799799

800800
let (mut fee_results, _) = process_state_transitions(
801801
&platform,

packages/rs-drive-abci/src/execution/platform_events/protocol_upgrade/upgrade_protocol_version/v0/mod.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,19 @@ impl<C> Platform<C> {
9999
// If cached_fee_version is non-empty
100100
if let Some((_, last_fee_version)) = previous_fee_versions_map.iter().last() {
101101
// Insert the new (epoch_index, fee_version) only if the new fee_version is different from the last_fee_version.
102-
if *last_fee_version != platform_version.fee_version {
102+
if last_fee_version.fee_version_number
103+
!= platform_version.fee_version.fee_version_number
104+
{
103105
previous_fee_versions_map.insert(
104106
epoch_info.current_epoch_index(),
105-
platform_version.fee_version.clone(),
107+
&platform_version.fee_version,
106108
);
107109
}
108110
// In case of empty cached_fee_version, insert the new (epoch_index, fee_version)
109111
} else {
110112
previous_fee_versions_map.insert(
111113
epoch_info.current_epoch_index(),
112-
platform_version.fee_version.clone(),
114+
&platform_version.fee_version,
113115
);
114116
}
115117

0 commit comments

Comments
 (0)