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
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions packages/js-dpp/lib/errors/consensus/codes.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const IncompatibleRe2PatternError = require('./basic/dataContract/IncompatibleRe
const InvalidDataContractVersionError = require('./basic/dataContract/InvalidDataContractVersionError');
const IncompatibleDataContractSchemaError = require('./basic/dataContract/IncompatibleDataContractSchemaError');
const DataContractImmutablePropertiesUpdateError = require('./basic/dataContract/DataContractImmutablePropertiesUpdateError');
const DataContractIndicesChangedError = require('./basic/dataContract/DataContractUniqueIndicesChangedError');
const DataContractUniqueIndicesChangedError = require('./basic/dataContract/DataContractUniqueIndicesChangedError');
const DuplicateIndexNameError = require('./basic/dataContract/DuplicateIndexNameError');
const DataContractInvalidIndexDefinitionUpdateError = require('./basic/dataContract/DataContractInvalidIndexDefinitionUpdateError');
const DataContractHaveNewUniqueIndexError = require('./basic/dataContract/DataContractHaveNewUniqueIndexError');
Expand Down Expand Up @@ -116,7 +116,7 @@ const codes = {
1050: InvalidDataContractVersionError,
1051: IncompatibleDataContractSchemaError,
1052: DataContractImmutablePropertiesUpdateError,
1053: DataContractIndicesChangedError,
1053: DataContractUniqueIndicesChangedError,
1054: DataContractInvalidIndexDefinitionUpdateError,
1055: DataContractHaveNewUniqueIndexError,

Expand Down
Original file line number Diff line number Diff line change
@@ -1,41 +1,42 @@
use anyhow::anyhow;
use serde_json::Value as JsonValue;
use sha2::digest::generic_array::functional::FunctionalSequence;
use std::collections::{hash_map::Entry, HashMap};

use crate::document::document_transition::{DocumentBaseTransition, DocumentTransition};
use crate::document::document_transition::{
DocumentBaseTransition, DocumentTransition, DocumentTransitionObjectLike,
};
use crate::util::string_encoding::Encoding;

/// Find the duplicates in the collection of Document Transitions
pub fn find_duplicates_by_id<'a>(
document_transitions: impl IntoIterator<Item = &'a DocumentTransition>,
) -> Vec<&'a DocumentTransition> {
let mut fingerprints: HashMap<String, ()> = HashMap::new();
let mut duplicates: Vec<&DocumentTransition> = vec![];
document_transitions: impl IntoIterator<Item = &'a JsonValue>,
) -> Result<Vec<JsonValue>, anyhow::Error> {
let mut fingerprints: HashMap<String, JsonValue> = HashMap::new();
let mut duplicates: Vec<JsonValue> = vec![];

for dt in document_transitions {
match fingerprints.entry(create_fingerprint(dt)) {
Entry::Occupied(_) => {
duplicates.push(dt);
for transition in document_transitions {
let fingerprint = create_fingerprint(&transition).ok_or(anyhow!(
"Can't create fingerprint from a document transition"
))?;
match fingerprints.entry(fingerprint.clone()) {
Entry::Occupied(val) => {
duplicates.push(val.get().clone());
}
Entry::Vacant(v) => {
v.insert(());
v.insert(transition.clone());
}
}
}
duplicates
Ok(duplicates)
}

fn create_fingerprint(document_transition: &DocumentTransition) -> String {
match document_transition {
DocumentTransition::Create(ref dt) => fingerprint(&dt.base),
DocumentTransition::Delete(ref dt) => fingerprint(&dt.base),
DocumentTransition::Replace(ref dt) => fingerprint(&dt.base),
}
}
fn fingerprint(document: &DocumentBaseTransition) -> String {
format!(
fn create_fingerprint(document_transition: &JsonValue) -> Option<String> {
Some(format!(
"{}:{}",
document.data_contract_id.to_string(Encoding::Base58),
document.document_type
)
document_transition.as_object()?.get("$type")?,
document_transition.as_object()?.get("id")?,
))
}

#[cfg(test)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::{
convert::{TryFrom, TryInto},
};

use crate::document::validation::basic::find_duplicates_by_id::find_duplicates_by_id;
use crate::{
consensus::basic::BasicError,
data_contract::{
Expand Down Expand Up @@ -209,7 +210,7 @@ fn validate_raw_transitions<'a>(
for raw_document_transition in raw_document_transitions.iter() {
let document_type = match raw_document_transition.get_string("$type") {
Err(_) => {
result.add_error(BasicError::MissingDocumentTypeError);
result.add_error(BasicError::MissingDocumentTransitionTypeError);
return Ok(result);
}

Expand Down Expand Up @@ -292,8 +293,7 @@ fn validate_raw_transitions<'a>(

let raw_document_transitions_iter = raw_document_transitions.into_iter();

let duplicate_transitions =
find_duplicates_by_indices(raw_document_transitions_iter.clone(), data_contract)?;
let duplicate_transitions = find_duplicates_by_id(raw_document_transitions_iter.clone())?;
if !duplicate_transitions.is_empty() {
let references: Vec<(String, Vec<u8>)> = duplicate_transitions
.iter()
Expand All @@ -306,6 +306,20 @@ fn validate_raw_transitions<'a>(
result.add_error(BasicError::DuplicateDocumentTransitionsWithIdsError { references });
}

let duplicate_transitions_by_indices =
find_duplicates_by_indices(raw_document_transitions_iter.clone(), data_contract)?;
if !duplicate_transitions_by_indices.is_empty() {
let references: Vec<(String, Vec<u8>)> = duplicate_transitions_by_indices
.iter()
.map(|t| {
let doc_type = t.get_string("$type")?.to_string();
let id = t.get_bytes("$id")?;
Ok((doc_type, id))
})
.collect::<Result<Vec<(String, Vec<u8>)>, anyhow::Error>>()?;
result.add_error(BasicError::DuplicateDocumentTransitionsWithIndicesError { references });
}

let validation_result = validate_partial_compound_indices(
raw_document_transitions_iter
.clone()
Expand Down
10 changes: 6 additions & 4 deletions packages/rs-dpp/src/errors/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ impl ErrorWithCode for ConsensusError {
Self::IncompatibleProtocolVersionError(_) => 1003,

// Identity
Self::DuplicatedIdentityPublicKeyError(_) => 1029,
Self::DuplicatedIdentityPublicKeyIdError(_) => 1030,
Self::DuplicatedIdentityPublicKeyBasicError(_) => 1029,
Self::DuplicatedIdentityPublicKeyBasicIdError(_) => 1030,
Self::IdentityAssetLockProofLockedTransactionMismatchError(_) => 1031,
Self::IdentityAssetLockTransactionIsNotFoundError(_) => 1032,
Self::IdentityAssetLockTransactionOutPointAlreadyExistsError(_) => 1033,
Expand Down Expand Up @@ -103,12 +103,14 @@ impl ErrorWithCode for BasicError {
// Document
Self::DataContractNotPresent { .. } => 1018,
Self::InvalidDocumentTypeError { .. } => 1024,
Self::MissingDocumentTypeError { .. } => 1027,
Self::MissingDocumentTransitionTypeError { .. } => 1027,
Self::MissingDocumentTransitionActionError { .. } => 1026,
Self::MissingDocumentTypeError => 1028,
Self::InvalidDocumentTransitionIdError { .. } => 1023,
Self::InvalidDocumentTransitionActionError { .. } => 1022,

Self::DuplicateDocumentTransitionsWithIdsError { .. } => 1019,
Self::DuplicateDocumentTransitionsWithIndicesError { .. } => 1020,
Self::MissingDataContractIdError => 1025,
Self::InvalidIdentifierError { .. } => 1006,

Expand All @@ -122,7 +124,7 @@ impl ErrorWithCode for BasicError {
Self::DataContractImmutablePropertiesUpdateError { .. } => 1052,
Self::IncompatibleDataContractSchemaError { .. } => 1051,

Self::DataContractUniqueIndicesChangedError { .. } => 4016,
Self::DataContractUniqueIndicesChangedError { .. } => 1053,
// TODO - they don't have error codes in https://github.com/dashevo/platform/blob/25ab6d8a38880eaff6ac119126b2ee5991b2a5aa/packages/js-dpp/lib/errors/consensus/codes.js
Self::DataContractHaveNewUniqueIndexError { .. } => 0,
Self::DataContractInvalidIndexDefinitionUpdateError { .. } => 0,
Expand Down
12 changes: 6 additions & 6 deletions packages/rs-dpp/src/errors/consensus/abstract_consensus_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,13 @@ pub enum ConsensusError {
#[error("{0}")]
IncompatibleProtocolVersionError(IncompatibleProtocolVersionError),
#[error("{0}")]
DuplicatedIdentityPublicKeyIdError(DuplicatedIdentityPublicKeyIdError),
DuplicatedIdentityPublicKeyBasicIdError(DuplicatedIdentityPublicKeyIdError),
#[error("{0}")]
InvalidIdentityPublicKeyDataError(InvalidIdentityPublicKeyDataError),
#[error("{0}")]
InvalidIdentityPublicKeySecurityLevelError(InvalidIdentityPublicKeySecurityLevelError),
#[error("{0}")]
DuplicatedIdentityPublicKeyError(DuplicatedIdentityPublicKeyError),
DuplicatedIdentityPublicKeyBasicError(DuplicatedIdentityPublicKeyError),
#[error("{0}")]
MissingMasterPublicKeyError(MissingMasterPublicKeyError),
#[error("{0}")]
Expand Down Expand Up @@ -144,8 +144,8 @@ impl ConsensusError {
ConsensusError::IncompatibleProtocolVersionError(_) => 1003,

// Identity
ConsensusError::DuplicatedIdentityPublicKeyError(_) => 1029,
ConsensusError::DuplicatedIdentityPublicKeyIdError(_) => 1030,
ConsensusError::DuplicatedIdentityPublicKeyBasicError(_) => 1029,
ConsensusError::DuplicatedIdentityPublicKeyBasicIdError(_) => 1030,
ConsensusError::IdentityAssetLockProofLockedTransactionMismatchError(_) => 1031,
ConsensusError::IdentityAssetLockTransactionIsNotFoundError(_) => 1032,
ConsensusError::IdentityAssetLockTransactionOutPointAlreadyExistsError(_) => 1033,
Expand Down Expand Up @@ -204,7 +204,7 @@ impl From<IncompatibleProtocolVersionError> for ConsensusError {

impl From<DuplicatedIdentityPublicKeyIdError> for ConsensusError {
fn from(error: DuplicatedIdentityPublicKeyIdError) -> Self {
Self::DuplicatedIdentityPublicKeyIdError(error)
Self::DuplicatedIdentityPublicKeyBasicIdError(error)
}
}

Expand All @@ -222,7 +222,7 @@ impl From<InvalidIdentityPublicKeySecurityLevelError> for ConsensusError {

impl From<DuplicatedIdentityPublicKeyError> for ConsensusError {
fn from(error: DuplicatedIdentityPublicKeyError) -> Self {
Self::DuplicatedIdentityPublicKeyError(error)
Self::DuplicatedIdentityPublicKeyBasicError(error)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ pub enum BasicError {
document_type: String,
},

#[error("$type is not present")]
MissingDocumentTransitionTypeError,

#[error("$type is not present")]
MissingDocumentTypeError,

Expand All @@ -69,6 +72,12 @@ pub enum BasicError {
#[error("Document transitions with duplicate IDs {:?}", references)]
DuplicateDocumentTransitionsWithIdsError { references: Vec<(String, Vec<u8>)> },

#[error(
"Document transitions with duplicate unique properties: {:?}",
references
)]
DuplicateDocumentTransitionsWithIndicesError { references: Vec<(String, Vec<u8>)> },

#[error("$dataContractId is not present")]
MissingDataContractIdError,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,7 @@ pub fn should_return_invalid_result_if_there_are_duplicate_key_ids() {

let errors = assert_consensus_errors!(
result,
ConsensusError::DuplicatedIdentityPublicKeyIdError,
ConsensusError::DuplicatedIdentityPublicKeyBasicIdError,
1
);
let consensus_error = result.errors().first().unwrap();
Expand Down Expand Up @@ -372,8 +372,11 @@ pub fn should_return_invalid_result_if_there_are_duplicate_keys() {
);

let result = validator.validate_keys(&raw_public_keys).unwrap();
let errors =
assert_consensus_errors!(&result, ConsensusError::DuplicatedIdentityPublicKeyError, 1);
let errors = assert_consensus_errors!(
&result,
ConsensusError::DuplicatedIdentityPublicKeyBasicError,
1
);

let consensus_error = result.errors().first().unwrap();
let error = errors.get(0).unwrap();
Expand Down
2 changes: 1 addition & 1 deletion packages/rs-drive/src/common/helpers/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ pub fn setup_drive(drive_config: Option<DriveConfig>) -> Drive {

/// Sets up Drive with the initial state structure.
pub fn setup_drive_with_initial_state_structure() -> Drive {
let drive = setup_drive(Some(DriveConfig{
let drive = setup_drive(Some(DriveConfig {
batching_consistency_verification: true,
..Default::default()
}));
Expand Down
6 changes: 5 additions & 1 deletion packages/rs-drive/src/drive/object_size_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,11 @@ impl<'a, const N: usize> PathKeyInfo<'a, N> {
(*path_iterator).iter().map(|a| a.len() as u32).sum::<u32>() + key.len() as u32
}
PathKeySize(key_info_path, key_size) => {
key_info_path.iterator().map(|a| a.max_length() as u32).sum::<u32>() + key_size.max_length() as u32
key_info_path
.iterator()
.map(|a| a.max_length() as u32)
.sum::<u32>()
+ key_size.max_length() as u32
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions packages/rs-drive/src/query/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1257,8 +1257,8 @@ impl<'a> DriveQuery<'a> {
let element = Element::deserialize(value).unwrap();
match element {
Element::Item(val, _) => values.push(val),
| Element::SumItem(val, _) => values.push(val.to_be_bytes().to_vec()),
Element::Tree(..) | Element::SumTree(..) | Element::Reference(..) => {
Element::SumItem(val, _) => values.push(val.to_be_bytes().to_vec()),
Element::Tree(..) | Element::SumTree(..) | Element::Reference(..) => {
return Err(Error::GroveDB(GroveError::InvalidQuery(
"path query should only point to items: got trees",
)));
Expand Down
6 changes: 4 additions & 2 deletions packages/rs-drive/tests/query_tests_history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,8 @@ fn test_query_historical() {
assert_eq!(
root_hash.as_slice(),
vec![
49, 205, 177, 218, 169, 224, 236, 206, 112, 34, 163, 112, 222, 73, 92, 82, 189, 120, 135, 32, 13, 65, 253, 139, 167, 209, 146, 1, 81, 127, 38, 61
49, 205, 177, 218, 169, 224, 236, 206, 112, 34, 163, 112, 222, 73, 92, 82, 189, 120,
135, 32, 13, 65, 253, 139, 167, 209, 146, 1, 81, 127, 38, 61
]
);

Expand Down Expand Up @@ -1534,7 +1535,8 @@ fn test_query_historical() {
assert_eq!(
root_hash.as_slice(),
vec![
200, 234, 81, 179, 120, 70, 117, 20, 202, 219, 197, 168, 20, 96, 55, 130, 62, 243, 181, 198, 88, 50, 225, 68, 205, 54, 191, 136, 37, 65, 113, 200
200, 234, 81, 179, 120, 70, 117, 20, 202, 219, 197, 168, 20, 96, 55, 130, 62, 243, 181,
198, 88, 50, 225, 68, 205, 54, 191, 136, 37, 65, 113, 200
]
);
}
24 changes: 24 additions & 0 deletions packages/wasm-dpp/lib/dpp.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as dpp_module from '../wasm/wasm_dpp';
import { patchConsensusErrors } from './errors/patchConsensusErrors';

patchConsensusErrors();

// While we declared it above, those fields do not hold any values - let's assign them.
// We need to suppress the compiler here, as he won't be happy about those reassignments.
// @ts-ignore
dpp_module.IdentityPublicKey.TYPES = dpp_module.KeyType;
// @ts-ignore
dpp_module.IdentityPublicKey.PURPOSES = dpp_module.KeyPurpose;
// @ts-ignore
dpp_module.IdentityPublicKey.SECURITY_LEVELS = dpp_module.KeySecurityLevel;

export * from '../wasm/wasm_dpp';
export * from './errors/AbstractConsensusError';
export * from './errors/DPPError';

// Declarations written prior to "export *" will overwrite exports
export declare class IdentityPublicKey extends dpp_module.IdentityPublicKey {
static TYPES: typeof dpp_module.KeyType;
static PURPOSES: typeof dpp_module.KeyPurpose;
static SECURITY_LEVELS: typeof dpp_module.KeySecurityLevel;
}
13 changes: 13 additions & 0 deletions packages/wasm-dpp/lib/errors/AbstractConsensusError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { DPPError } from './DPPError'

/**
* @abstract
*/
export class AbstractConsensusError extends DPPError {
/**
* @param {string} message
*/
constructor(message: string) {
super(message);
}
}
15 changes: 15 additions & 0 deletions packages/wasm-dpp/lib/errors/DPPError.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export class DPPError extends Error {
name: string;
message: string;

constructor(message: string) {
super();

this.name = this.constructor.name;
this.message = message;

if (Error.captureStackTrace) {
Error.captureStackTrace(this, this.constructor);
}
}
}
Loading