Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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: 2 additions & 0 deletions packages/rs-dpp/src/errors/consensus/codes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ impl ErrorWithCode for StateError {
Self::RequiredTokenPaymentInfoNotSetError(_) => 40115,
Self::IdentityHasNotAgreedToPayRequiredTokenAmountError(_) => 40116,
Self::IdentityTryingToPayWithWrongTokenError(_) => 40117,
Self::DocumentContestIndexMismatchError(_) => 40118,
Self::DocumentContestNotRequiredError(_) => 40119,

// Identity Errors: 40200-40299
Self::IdentityAlreadyExistsError(_) => 40200,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
use crate::consensus::state::state_error::StateError;
use crate::consensus::ConsensusError;
use crate::errors::ProtocolError;
use bincode::{Decode, Encode};
use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
use platform_value::Identifier;
use thiserror::Error;

#[derive(
Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize,
)]
#[error("Contest for document {document_id} prefunded the voting balance of index {provided_index_name}, but the contested index resolved for this document is {expected_index_name}")]
#[platform_serialize(unversioned)]
pub struct DocumentContestIndexMismatchError {
/*

DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION

*/
document_id: Identifier,

expected_index_name: String,

provided_index_name: String,
}

impl DocumentContestIndexMismatchError {
pub fn new(
document_id: Identifier,
expected_index_name: String,
provided_index_name: String,
) -> Self {
Self {
document_id,
expected_index_name,
provided_index_name,
}
}

pub fn document_id(&self) -> &Identifier {
&self.document_id
}

pub fn expected_index_name(&self) -> &str {
&self.expected_index_name
}

pub fn provided_index_name(&self) -> &str {
&self.provided_index_name
}
}

impl From<DocumentContestIndexMismatchError> for ConsensusError {
fn from(err: DocumentContestIndexMismatchError) -> Self {
Self::StateError(StateError::DocumentContestIndexMismatchError(err))
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
use crate::consensus::state::state_error::StateError;
use crate::consensus::ConsensusError;
use crate::errors::ProtocolError;
use bincode::{Decode, Encode};
use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
use platform_value::Identifier;
use thiserror::Error;

#[derive(
Error, Debug, Clone, PartialEq, Eq, Encode, Decode, PlatformSerialize, PlatformDeserialize,
)]
#[error("Document {document_id} prefunded the voting balance of index {provided_index_name}, but this document does not resolve to a contested index")]
#[platform_serialize(unversioned)]
pub struct DocumentContestNotRequiredError {
/*

DO NOT CHANGE ORDER OF FIELDS WITHOUT INTRODUCING OF NEW VERSION

*/
document_id: Identifier,

provided_index_name: String,
}

impl DocumentContestNotRequiredError {
pub fn new(document_id: Identifier, provided_index_name: String) -> Self {
Self {
document_id,
provided_index_name,
}
}

pub fn document_id(&self) -> &Identifier {
&self.document_id
}

pub fn provided_index_name(&self) -> &str {
&self.provided_index_name
}
}

impl From<DocumentContestNotRequiredError> for ConsensusError {
fn from(err: DocumentContestNotRequiredError) -> Self {
Self::StateError(StateError::DocumentContestNotRequiredError(err))
}
}
2 changes: 2 additions & 0 deletions packages/rs-dpp/src/errors/consensus/state/document/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ pub mod document_already_present_error;
pub mod document_contest_currently_locked_error;
pub mod document_contest_document_with_same_id_already_present_error;
pub mod document_contest_identity_already_contestant;
pub mod document_contest_index_mismatch_error;
pub mod document_contest_not_joinable_error;
pub mod document_contest_not_paid_for_error;
pub mod document_contest_not_required_error;
pub mod document_incorrect_purchase_price_error;
pub mod document_not_for_sale_error;
pub mod document_not_found_error;
Expand Down
69 changes: 69 additions & 0 deletions packages/rs-dpp/src/errors/consensus/state/state_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,10 @@ use crate::consensus::state::data_contract::document_type_update_error::Document
use crate::consensus::state::document::document_contest_currently_locked_error::DocumentContestCurrentlyLockedError;
use crate::consensus::state::document::document_contest_document_with_same_id_already_present_error::DocumentContestDocumentWithSameIdAlreadyPresentError;
use crate::consensus::state::document::document_contest_identity_already_contestant::DocumentContestIdentityAlreadyContestantError;
use crate::consensus::state::document::document_contest_index_mismatch_error::DocumentContestIndexMismatchError;
use crate::consensus::state::document::document_contest_not_joinable_error::DocumentContestNotJoinableError;
use crate::consensus::state::document::document_contest_not_paid_for_error::DocumentContestNotPaidForError;
use crate::consensus::state::document::document_contest_not_required_error::DocumentContestNotRequiredError;
use crate::consensus::state::document::document_incorrect_purchase_price_error::DocumentIncorrectPurchasePriceError;
use crate::consensus::state::document::document_not_for_sale_error::DocumentNotForSaleError;
use crate::consensus::state::group::{GroupActionAlreadyCompletedError, GroupActionAlreadySignedByIdentityError, GroupActionDoesNotExistError, IdentityMemberOfGroupNotFoundError, IdentityNotMemberOfGroupError, ModificationOfGroupActionMainParametersNotPermittedError};
Expand Down Expand Up @@ -354,10 +356,77 @@ pub enum StateError {

#[error(transparent)]
InsufficientShieldedFeeError(InsufficientShieldedFeeError),

#[error(transparent)]
DocumentContestIndexMismatchError(DocumentContestIndexMismatchError),

#[error(transparent)]
DocumentContestNotRequiredError(DocumentContestNotRequiredError),
}

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

#[cfg(test)]
mod tests {
use super::*;
use platform_value::Identifier;

/// `StateError` is encoded by variant position, so inserting a variant
/// anywhere but the end silently reassigns the discriminant of every
/// variant after it — consensus errors travel to WASM and JavaScript
/// clients, which would then decode an existing error as a different one.
/// These are the frozen discriminants of the first variant, of the variant
/// that follows the document contest block (the one an insertion there
/// would shift first), and of the last two.
fn discriminant_of(error: StateError) -> u8 {
let bytes = bincode::encode_to_vec(error, bincode::config::standard())
.expect("expected to encode the state error");
// Discriminants below 251 are a single byte under bincode's varint.
bytes[0]
}

#[test]
fn state_error_discriminants_are_frozen() {
assert_eq!(
discriminant_of(StateError::DataContractAlreadyPresentError(
DataContractAlreadyPresentError::new(Identifier::from([1; 32]))
)),
0
);
assert_eq!(
discriminant_of(StateError::DocumentNotFoundError(
DocumentNotFoundError::new(Identifier::from([1; 32]))
)),
8
);
assert_eq!(
discriminant_of(StateError::InsufficientShieldedFeeError(
InsufficientShieldedFeeError::new("fee".to_string())
)),
90
);
assert_eq!(
discriminant_of(StateError::DocumentContestIndexMismatchError(
DocumentContestIndexMismatchError::new(
Identifier::from([1; 32]),
"expected".to_string(),
"provided".to_string(),
)
)),
91
);
assert_eq!(
discriminant_of(StateError::DocumentContestNotRequiredError(
DocumentContestNotRequiredError::new(
Identifier::from([1; 32]),
"provided".to_string(),
)
)),
92
);
}
}
Loading
Loading