Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(wasm-dpp): serialization bugs and failing tests #1030

Merged
merged 8 commits into from
May 5, 2023
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
4 changes: 2 additions & 2 deletions packages/rs-dpp/src/data_contract/data_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ use bincode::de::{BorrowDecoder, Decoder};
use bincode::enc::Encoder;
use bincode::error::{DecodeError, EncodeError};
use bincode::{BorrowDecode, Decode, Encode};
use futures::StreamExt;

use std::collections::{BTreeMap, HashSet};
use std::convert::{TryFrom, TryInto};

use crate::serialization_traits::{PlatformDeserializable, PlatformSerializable, ValueConvertible};
use crate::serialization_traits::{PlatformDeserializable, PlatformSerializable};
use itertools::{Either, Itertools};
use platform_value::btreemap_extensions::{BTreeValueMapHelper, BTreeValueRemoveFromMapHelper};
use platform_value::{Bytes32, Identifier};
Expand Down
40 changes: 22 additions & 18 deletions packages/rs-dpp/src/data_contract/data_contract_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,7 @@ impl DataContractFactory {
skip_validation: bool,
) -> Result<DataContract, ProtocolError> {
if !skip_validation {
let result = self
.validate_data_contract
.validate(&data_contract_object)?;

if !result.is_valid() {
return Err(ProtocolError::InvalidDataContractError(
InvalidDataContractError::new(result.errors, data_contract_object),
));
}
self.validate_data_contract(&data_contract_object)?;
}
if !data_contract_object
.has(PROTOCOL_VERSION)
Expand All @@ -167,18 +159,30 @@ impl DataContractFactory {
buffer: Vec<u8>,
skip_validation: bool,
) -> Result<DataContract, ProtocolError> {
let data_contract = DataContract::deserialize(buffer.as_slice()).map_err(|e| {
ConsensusError::BasicError(BasicError::SerializedObjectParsingError(
SerializedObjectParsingError::new(format!("Decode protocol entity: {:#?}", e)),
))
})?;
let data_contract: DataContract =
DataContract::deserialize(buffer.as_slice()).map_err(|e| {
ConsensusError::BasicError(BasicError::SerializedObjectParsingError(
SerializedObjectParsingError::new(format!("Decode protocol entity: {:#?}", e)),
))
})?;

if !skip_validation {
let value = data_contract.to_object()?;
self.create_from_object(value, skip_validation).await
} else {
Ok(data_contract)
self.validate_data_contract(&data_contract.to_cleaned_object()?)?;
}

Ok(data_contract)
}

pub fn validate_data_contract(&self, raw_data_contract: &Value) -> Result<(), ProtocolError> {
let result = self.validate_data_contract.validate(raw_data_contract)?;

if !result.is_valid() {
return Err(ProtocolError::InvalidDataContractError(
InvalidDataContractError::new(result.errors, raw_data_contract.to_owned()),
));
}

Ok(())
}

pub fn create_data_contract_create_transition(
Expand Down
30 changes: 13 additions & 17 deletions packages/rs-dpp/src/document/document_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,18 @@ use platform_value::{Bytes32, ReplacementType, Value};
use serde::{Deserialize, Serialize};

use crate::consensus::basic::document::InvalidDocumentTypeError;
use crate::document::extended_document::{property_names, ExtendedDocument};
use crate::document::extended_document::ExtendedDocument;

use crate::consensus::basic::decode::SerializedObjectParsingError;
use crate::consensus::basic::BasicError;
use crate::consensus::ConsensusError;
use crate::document::document_transition::INITIAL_REVISION;
use crate::document::Document;
use crate::identity::TimestampMillis;
use crate::serialization_traits::PlatformDeserializable;
use crate::util::entropy_generator::{DefaultEntropyGenerator, EntropyGenerator};
use crate::{
data_contract::{errors::DataContractError, DataContract},
encoding::decode_protocol_entity_factory::DecodeProtocolEntity,
prelude::Identifier,
state_repository::StateRepositoryLike,
ProtocolError,
Expand Down Expand Up @@ -272,21 +275,14 @@ where
buffer: impl AsRef<[u8]>,
options: FactoryOptions,
) -> Result<ExtendedDocument, ProtocolError> {
let result =
DecodeProtocolEntity::decode_protocol_entity_to_value::<ExtendedDocument>(buffer);

match result {
Err(ProtocolError::ConsensusError(err)) => Err(DocumentError::InvalidDocumentError {
errors: vec![*err],
raw_document: Value::Null,
}
.into()),
Err(err) => Err(err),
Ok((version, mut raw_document)) => {
raw_document.set_value(property_names::PROTOCOL_VERSION, Value::U32(version))?;
self.create_from_object(raw_document, options).await
}
}
let document = <ExtendedDocument as PlatformDeserializable>::deserialize(buffer.as_ref())
.map_err(|e| {
ConsensusError::BasicError(BasicError::SerializedObjectParsingError(
SerializedObjectParsingError::new(format!("Decode protocol entity: {:#?}", e)),
))
})?;

self.create_from_object(document.to_value()?, options).await
}

pub async fn create_from_object(
Expand Down
60 changes: 49 additions & 11 deletions packages/rs-dpp/src/document/extended_document.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,13 @@ use integer_encoding::VarInt;
use crate::data_contract::document_type::document_type::PROTOCOL_VERSION;
use crate::data_contract::document_type::DocumentType;
use crate::document::Document;
use crate::serialization_traits::PlatformDeserializable;
use crate::serialization_traits::ValueConvertible;
use crate::serialization_traits::{PlatformDeserializable, PlatformSerializable};
use bincode::de::Decoder;
use bincode::enc::Encoder;
use bincode::error::{DecodeError, EncodeError};
use bincode::{config, Decode, Encode};
use platform_serialization::{PlatformDeserialize, PlatformSerialize};

use platform_value::btreemap_extensions::BTreeValueMapInsertionPathHelper;
use platform_value::btreemap_extensions::BTreeValueMapPathHelper;
Expand Down Expand Up @@ -49,7 +54,8 @@ pub const IDENTIFIER_FIELDS: [&str; 3] = [
];

/// The document object represents the data provided by the platform in response to a query.
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
#[derive(Serialize, Deserialize, Debug, Clone, Default, PlatformDeserialize, PlatformSerialize)]
#[platform_error_type(ProtocolError)]
pub struct ExtendedDocument {
#[serde(rename = "$protocolVersion")]
pub protocol_version: u32,
Expand All @@ -68,6 +74,47 @@ pub struct ExtendedDocument {
pub entropy: Bytes32,
}

impl Encode for ExtendedDocument {
fn encode<E: Encoder>(&self, encoder: &mut E) -> Result<(), EncodeError> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure how it works - is the data being written to the encoder directly and then something like encoder.finalize() is called?

Copy link
Member

Choose a reason for hiding this comment

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

Well yes, when you derive Encode it takes every attribute and encodes them and puts them back to back, but you don't need to derive, you can do things manually.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm more interested in how the API works. For example, if you want to serialize something to a vec, you write something like let encoded: Vec<u8> = bincode::serialize(&doc).unwrap();, and then bincode figures out the encoder internally? I'm not really familiar with the barcode just yet, so I was wondering if my assumption is right

Copy link
Collaborator

@antouhou antouhou May 5, 2023

Choose a reason for hiding this comment

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

This is not exactly a comment to this specific code, just figured that this is the place I can ask about it as well :)

self.data_contract.encode(encoder)?;
self.document_type_name.encode(encoder)?;
let serialized_document = self
.document
.serialize(
self.data_contract
.document_type_for_name(&self.document_type_name)
.map_err(|e| EncodeError::OtherString(e.to_string()))?,
)
.map_err(|e| EncodeError::OtherString(e.to_string()))?;
serialized_document.encode(encoder)?;
Ok(())
}
}

impl Decode for ExtendedDocument {
fn decode<D: Decoder>(decoder: &mut D) -> Result<Self, DecodeError> {
let data_contract = DataContract::decode(decoder)?;
let document_type_name = String::decode(decoder)?;
let document_bytes = Vec::<u8>::decode(decoder)?;
let document = Document::from_bytes(
&document_bytes,
data_contract
.document_type_for_name(&document_type_name)
.map_err(|e| DecodeError::OtherString(e.to_string()))?,
)
.map_err(|e| DecodeError::OtherString(e.to_string()))?;
Ok(Self {
protocol_version: PROTOCOL_VERSION,
data_contract_id: data_contract.id,
data_contract,
document_type_name,
document,
metadata: None,
entropy: Bytes32::default(),
})
}
}

impl ExtendedDocument {
fn properties_as_json_data(&self) -> Result<JsonValue, ProtocolError> {
self.document
Expand Down Expand Up @@ -429,15 +476,6 @@ impl ExtendedDocument {
}
}

impl PlatformDeserializable for ExtendedDocument {
fn deserialize(_data: &[u8]) -> Result<Self, ProtocolError>
where
Self: Sized,
{
todo!()
}
}

impl ValueConvertible for ExtendedDocument {
fn to_object(&self) -> Result<Value, ProtocolError> {
todo!()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ use platform_value::Value;
use crate::consensus::basic::decode::SerializedObjectParsingError;
use crate::consensus::basic::BasicError;
use crate::serialization_traits::{PlatformDeserializable, ValueConvertible};
use crate::state_transition::StateTransitionConvert;
use crate::util::deserializer;
use crate::util::deserializer::SplitProtocolVersionOutcome;
use crate::{errors::consensus::ConsensusError, errors::ProtocolError, Convertible};
use crate::{errors::consensus::ConsensusError, errors::ProtocolError};

#[derive(Default, Clone, Copy)]
pub struct DecodeProtocolEntity {}
Expand Down
47 changes: 21 additions & 26 deletions packages/rs-dpp/src/identity/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,6 @@ use crate::consensus::basic::BasicError;
use crate::consensus::ConsensusError;
use crate::serialization_traits::PlatformDeserializable;

use crate::util::deserializer;
use crate::util::deserializer::SplitProtocolVersionOutcome;

use platform_value::Value;
use std::sync::Arc;

Expand Down Expand Up @@ -190,16 +187,7 @@ where
skip_validation: bool,
) -> Result<Identity, ProtocolError> {
if !skip_validation {
let result = self
.identity_validator
.validate_identity_object(&raw_identity)?;

if !result.is_valid() {
return Err(ProtocolError::InvalidIdentityError {
errors: result.errors,
raw_identity,
});
}
self.validate_identity(&raw_identity)?;
}

Identity::from_object(raw_identity)
Expand All @@ -210,25 +198,32 @@ where
buffer: Vec<u8>,
skip_validation: bool,
) -> Result<Identity, ProtocolError> {
let SplitProtocolVersionOutcome {
protocol_version,
main_message_bytes: document_bytes,
..
} = deserializer::split_protocol_version(buffer.as_ref())?;

let identity = Identity::deserialize(document_bytes).map_err(|e| {
let identity: Identity = Identity::deserialize(&buffer).map_err(|e| {
ConsensusError::BasicError(BasicError::SerializedObjectParsingError(
SerializedObjectParsingError::new(format!("Decode protocol entity: {:#?}", e)),
))
})?;

if skip_validation {
Ok(identity)
} else {
let mut value = identity.to_object()?;
value.set_value("protocolVersion", Value::U32(protocol_version))?;
self.create_from_object(value, false)
if !skip_validation {
self.validate_identity(&identity.to_cleaned_object()?)?;
}

Ok(identity)
}

pub fn validate_identity(&self, raw_identity: &Value) -> Result<(), ProtocolError> {
let result = self
.identity_validator
.validate_identity_object(raw_identity)?;

if !result.is_valid() {
return Err(ProtocolError::InvalidIdentityError {
errors: result.errors,
raw_identity: raw_identity.to_owned(),
});
}

Ok(())
}

pub fn create_instant_lock_proof(
Expand Down
67 changes: 33 additions & 34 deletions packages/rs-dpp/src/state_transition/state_transition_factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ use crate::identity::state_transition::identity_update_transition::identity_upda
use crate::serialization_traits::PlatformDeserializable;
use crate::state_transition::errors::StateTransitionError;
use crate::state_transition::StateTransitionConvert;
use crate::util::deserializer;
use crate::util::deserializer::SplitProtocolVersionOutcome;

use crate::{
consensus::{basic::BasicError, ConsensusError},
data_contract::{
Expand Down Expand Up @@ -87,21 +86,7 @@ where
let options = options.unwrap_or_default();

if !options.skip_validation {
let execution_context = StateTransitionExecutionContext::default();

let validation_result = self
.basic_validator
.validate(&raw_state_transition, &execution_context)
.await?;

if !validation_result.is_valid() {
return Err(ProtocolError::StateTransitionError(
StateTransitionError::InvalidStateTransitionError {
errors: validation_result.errors,
raw_state_transition,
},
));
}
self.validate_basic(&raw_state_transition).await?;
}

create_state_transition(self.state_repository.as_ref(), raw_state_transition).await
Expand All @@ -112,29 +97,43 @@ where
state_transition_buffer: &[u8],
options: Option<StateTransitionFactoryOptions>,
) -> Result<StateTransition, ProtocolError> {
let SplitProtocolVersionOutcome {
protocol_version,
main_message_bytes: document_bytes,
..
} = deserializer::split_protocol_version(state_transition_buffer)?;

let state_transition = StateTransition::deserialize(document_bytes).map_err(|e| {
ConsensusError::BasicError(BasicError::SerializedObjectParsingError(
SerializedObjectParsingError::new(format!("Decode protocol entity: {:#?}", e)),
))
})?;
let state_transition: StateTransition =
StateTransition::deserialize(state_transition_buffer).map_err(|e| {
ConsensusError::BasicError(BasicError::SerializedObjectParsingError(
SerializedObjectParsingError::new(format!("Decode protocol entity: {:#?}", e)),
))
})?;

if options
if !options
.as_ref()
.map(|options| options.skip_validation)
.unwrap_or_default()
{
Ok(state_transition)
} else {
let mut value = state_transition.to_object(false)?;
value.set_value("protocolVersion", Value::U32(protocol_version))?;
self.create_from_object(value, options).await
self.validate_basic(&state_transition.to_cleaned_object(false)?)
.await?;
}

Ok(state_transition)
}

pub async fn validate_basic(&self, raw_state_transition: &Value) -> Result<(), ProtocolError> {
let execution_context = StateTransitionExecutionContext::default();

let validation_result = self
.basic_validator
.validate(raw_state_transition, &execution_context)
.await?;

if !validation_result.is_valid() {
return Err(ProtocolError::StateTransitionError(
StateTransitionError::InvalidStateTransitionError {
errors: validation_result.errors,
raw_state_transition: raw_state_transition.to_owned(),
},
));
}

Ok(())
}
}

Expand Down
Loading