Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ json-patch = "0.2.6"
jsonptr = "0.1.5"
jsonschema = { git="https://github.com/fominok/jsonschema-rs", branch="feat-unevaluated-properties", default-features=false, features=["draft202012"] }
lazy_static = { version ="1.4"}
log = { version="0.4"}
log = { version = "0.4.6" }
num_enum = "0.5.7"
bincode = "1.3.3"
rand = { version = "0.8.4", features = ["small_rng"] }
Expand Down
32 changes: 29 additions & 3 deletions packages/rs-dpp/src/data_contract/data_contract.rs
Original file line number Diff line number Diff line change
Expand Up @@ -214,10 +214,36 @@ impl DataContract {
self.document_types.get(document_type_name).is_some()
}

pub fn set_document_schema(&mut self, doc_type: String, schema: JsonSchema) {
pub fn set_document_schema(
&mut self,
doc_type: String,
schema: JsonSchema,
) -> Result<(), ProtocolError> {
let binary_properties = get_binary_properties(&schema);
self.documents.insert(doc_type.clone(), schema);
self.binary_properties.insert(doc_type, binary_properties);
self.documents.insert(doc_type.clone(), schema.clone());
self.binary_properties
.insert(doc_type.clone(), binary_properties);

let document_type_value = platform_value::Value::from(schema);

// Make sure the document_type_value is a map
let Some(document_type_value_map) = document_type_value.as_map() else {
return Err(ProtocolError::DataContractError(DataContractError::InvalidContractStructure(
"document type data is not a map as expected",
)));
};

let document_type = DocumentType::from_platform_value(
&doc_type,
document_type_value_map,
&BTreeMap::new(),
self.config.documents_keep_history_contract_default,
self.config.documents_mutable_contract_default,
)?;

self.document_types.insert(doc_type, document_type);

Ok(())
}

pub fn get_document_schema(&self, doc_type: &str) -> Result<&JsonSchema, ProtocolError> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ where
state_transition: &DataContractUpdateTransition,
) -> Result<()> {
self.state_repository
.store_data_contract(
.update_data_contract(
state_transition.data_contract.clone(),
Some(state_transition.get_execution_context()),
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,6 @@ pub struct DataContractUpdateTransition {
pub protocol_version: u32,
#[serde(rename = "type")]
pub transition_type: StateTransitionType,
// we want to skip serialization of transitions, as we does it manually in `to_object()` and `to_json()`
#[serde(skip_serializing)]
pub data_contract: DataContract,
pub signature_public_key_id: KeyID,
pub signature: BinaryData,
Expand Down
22 changes: 12 additions & 10 deletions packages/rs-dpp/src/data_trigger/dpns_triggers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,13 +77,13 @@ where
.map_err(ProtocolError::ValueError)?;

let mut result = DataTriggerExecutionResult::default();
let full_domain_name = normalized_label;
let mut full_domain_name = normalized_label.to_string();

if !is_dry_run {
if full_domain_name.len() > MAX_PRINTABLE_DOMAIN_NAME_LENGTH {
let err = create_error(
context,
dt_create,
dt_create.base.id,
format!(
"Full domain name length can not be more than {} characters long but got {}",
MAX_PRINTABLE_DOMAIN_NAME_LENGTH,
Expand All @@ -96,7 +96,7 @@ where
if normalized_label != label.to_lowercase() {
let err = create_error(
context,
dt_create,
dt_create.base.id,
"Normalized label doesn't match label".to_string(),
);
result.add_error(err.into());
Expand All @@ -109,7 +109,7 @@ where
if id != owner_id {
let err = create_error(
context,
dt_create,
dt_create.base.id,
format!(
"ownerId {} doesn't match {} {}",
owner_id, PROPERTY_DASH_UNIQUE_IDENTITY_ID, id
Expand All @@ -126,7 +126,7 @@ where
if id != owner_id {
let err = create_error(
context,
dt_create,
dt_create.base.id,
format!(
"ownerId {} doesn't match {} {}",
owner_id, PROPERTY_DASH_ALIAS_IDENTITY_ID, id
Expand All @@ -139,14 +139,16 @@ where
if normalized_parent_domain_name.is_empty() && context.owner_id != top_level_identity {
let err = create_error(
context,
dt_create,
dt_create.base.id,
"Can't create top level domain for this identity".to_string(),
);
result.add_error(err.into())
}
}

if !normalized_parent_domain_name.is_empty() {
full_domain_name = format!("{full_domain_name}.{normalized_parent_domain_name}");

//? What is the `normalized_parent_name`. Are we sure the content is a valid dot-separated data
let mut parent_domain_segments = normalized_parent_domain_name.split('.');
let parent_domain_label = parent_domain_segments.next().unwrap().to_string();
Expand Down Expand Up @@ -175,7 +177,7 @@ where
if documents.is_empty() {
let err = create_error(
context,
dt_create,
dt_create.base.id,
"Parent domain is not present".to_string(),
);
result.add_error(err.into());
Expand All @@ -186,7 +188,7 @@ where
if rule_allow_subdomains {
let err = create_error(
context,
dt_create,
dt_create.base.id,
"Allowing subdomains registration is forbidden for non top level domains"
.to_string(),
);
Expand All @@ -200,7 +202,7 @@ where
{
let err = create_error(
context,
dt_create,
dt_create.base.id,
"The subdomain can be created only by the parent domain owner".to_string(),
);
result.add_error(err.into());
Expand Down Expand Up @@ -238,7 +240,7 @@ where
if preorder_documents.is_empty() {
let err = create_error(
context,
dt_create,
dt_create.base.id,
"preorderDocument was not found".to_string(),
);
result.add_error(err.into())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ where
if enable_at_height < block_height {
let err = create_error(
context,
dt_create,
dt_create.base.id,
"This identity can't activate selected feature flag".to_string(),
);
result.add_error(err.into());
Expand All @@ -65,7 +65,7 @@ where
if context.owner_id != top_level_identity {
let err = create_error(
context,
dt_create,
dt_create.base.id,
"This Identity can't activate selected feature flag".to_string(),
);
result.add_error(err.into());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ pub fn data_triggers() -> Result<Vec<DataTrigger>, ProtocolError> {
},
DataTrigger {
data_contract_id: master_node_reward_shares_contract_id,
document_type: feature_flags_contract::types::UPDATE_CONSENSUS_PARAMS.to_string(),
document_type: "rewardShare".to_string(),
Comment thread
markin-io marked this conversation as resolved.
Outdated
transition_action: Action::Create,
data_trigger_kind: DataTriggerKind::DataTriggerRewardShare,
top_level_identity: None,
Expand Down
4 changes: 2 additions & 2 deletions packages/rs-dpp/src/data_trigger/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,11 +147,11 @@ where

fn create_error<SR>(
context: &DataTriggerExecutionContext<SR>,
dt_create: &DocumentCreateTransition,
transition_id: Identifier,
msg: String,
) -> DataTriggerError
where
SR: StateRepositoryLike,
{
DataTriggerConditionError::new(context.data_contract.id, dt_create.base.id, msg).into()
DataTriggerConditionError::new(context.data_contract.id, transition_id, msg).into()
}
85 changes: 50 additions & 35 deletions packages/rs-dpp/src/data_trigger/reward_share_data_triggers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,38 +32,51 @@ where
let is_dry_run = context.state_transition_execution_context.is_dry_run();
let owner_id = context.owner_id.to_string(Encoding::Base58);

let document_create_transition = match document_transition {
DocumentTransition::Create(document_create_transition) => document_create_transition,
let (transition_data, transition_base) = match document_transition {
DocumentTransition::Create(document_create_transition) => (
document_create_transition.data.as_ref(),
&document_create_transition.base,
),
DocumentTransition::Replace(document_replace_transition) => (
document_replace_transition.data.as_ref(),
&document_replace_transition.base,
),
_ => bail!(
"the Document Transition {} isn't 'CREATE'",
"the Document Transition {} isn't 'CREATE or REPLACE'",
get_from_transition!(document_transition, id)
),
};
let properties = document_create_transition.data.as_ref().ok_or_else(|| {
let properties = transition_data.ok_or_else(|| {
anyhow!(
"data isn't defined in Data Transition '{}'",
document_create_transition.base.id
transition_base.id
)
})?;

let pay_to_id = properties.get_hash256_bytes(PROPERTY_PAY_TO_ID)?;
let percentage = properties.get_integer(PROPERTY_PERCENTAGE)?;

if !is_dry_run {
// Do not allow creating document if ownerId is not in SML
let sml_store: SMLStore = context.state_repository.fetch_sml_store().await?;

let valid_master_nodes_list = sml_store.get_current_sml()?.get_valid_master_nodes();

let owner_id_in_sml = valid_master_nodes_list.iter().any(|entry| {
hex::decode(&entry.pro_reg_tx_hash).expect("invalid hex value")
== context.owner_id.to_buffer()
});

if !owner_id_in_sml {
let is_valid_master_node = context
.state_repository
.is_in_the_valid_master_nodes_list(context.owner_id.to_buffer())
.await?;

// TODO: bring it back once the SML store is implemented
// // Do not allow creating document if ownerId is not in SML
// let sml_store: SMLStore = context.state_repository.fetch_sml_store().await?;
//
// let valid_master_nodes_list = sml_store.get_current_sml()?.get_valid_master_nodes();
//
// let owner_id_in_sml = valid_master_nodes_list.iter().any(|entry| {
// hex::decode(&entry.pro_reg_tx_hash).expect("invalid hex value")
// == context.owner_id.to_buffer()
// });

if !is_valid_master_node {
let err = create_error(
context,
document_create_transition,
transition_base.id,
"Only masternode identities can share rewards".to_string(),
);
result.add_error(err.into());
Expand All @@ -83,19 +96,20 @@ where
if !is_dry_run && maybe_identity.is_none() {
let err = create_error(
context,
document_create_transition,
transition_base.id,
format!("Identity '{}' doesn't exist", pay_to_identifier),
);
result.add_error(err.into())
result.add_error(err.into());
return Ok(result);
}

let documents_data = context
.state_repository
.fetch_documents(
&context.data_contract.id,
&document_create_transition.base.document_type_name,
&transition_base.document_type_name,
json!({
"where" : [ [ "$owner_id", "==", owner_id ]]
"where" : [ [ "$ownerId", "==", owner_id ]]
}),
Some(context.state_transition_execution_context),
)
Expand All @@ -112,7 +126,7 @@ where
if documents.len() >= MAX_DOCUMENTS {
let err = create_error(
context,
document_create_transition,
transition_base.id,
format!(
"Reward shares cannot contain more than {} identities",
MAX_DOCUMENTS
Expand All @@ -130,7 +144,7 @@ where
if total_percent > MAX_PERCENTAGE {
let err = create_error(
context,
document_create_transition,
transition_base.id,
format!("Percentage can not be more than {}", MAX_PERCENTAGE),
);
result.add_error(err.into());
Expand Down Expand Up @@ -246,6 +260,7 @@ mod test {
sml_store,
data_contract,
top_level_identifier,
identity,
..
} = setup_test();

Expand All @@ -257,11 +272,11 @@ mod test {

let mut state_repository_mock = MockStateRepositoryLike::new();
state_repository_mock
.expect_fetch_sml_store()
.returning(move || Ok(sml_store.clone()));
.expect_is_in_the_valid_master_nodes_list()
.returning(move |_| Ok(true));
state_repository_mock
.expect_fetch_identity()
.returning(|_, _| Ok(None));
.returning(move |_, _| Ok(Some(identity.clone())));
state_repository_mock
.expect_fetch_documents()
.returning(move |_, _, _, _| Ok(documents.clone()));
Expand All @@ -281,7 +296,7 @@ mod test {
create_masternode_reward_shares_data_trigger(&document_transition, &context, None)
.await;

let percentage_error = get_data_trigger_error(&result, 1);
let percentage_error = get_data_trigger_error(&result, 0);
assert_eq!(
"Percentage can not be more than 10000",
percentage_error.to_string()
Expand All @@ -300,8 +315,8 @@ mod test {

let mut state_repository_mock = MockStateRepositoryLike::new();
state_repository_mock
.expect_fetch_sml_store()
.returning(move || Ok(sml_store.clone()));
.expect_is_in_the_valid_master_nodes_list()
.returning(move |_| Ok(true));
state_repository_mock
.expect_fetch_identity()
.returning(move |_, _| Ok(None));
Expand Down Expand Up @@ -345,8 +360,8 @@ mod test {

let mut state_repository_mock = MockStateRepositoryLike::new();
state_repository_mock
.expect_fetch_sml_store()
.returning(move || Ok(sml_store.clone()));
.expect_is_in_the_valid_master_nodes_list()
.returning(move |_| Ok(false));
state_repository_mock
.expect_fetch_identity()
.returning(move |_, _| Ok(None));
Expand Down Expand Up @@ -385,8 +400,8 @@ mod test {

let mut state_repository_mock = MockStateRepositoryLike::new();
state_repository_mock
.expect_fetch_sml_store()
.returning(move || Ok(sml_store.clone()));
.expect_is_in_the_valid_master_nodes_list()
.returning(move |_| Ok(true));
state_repository_mock
.expect_fetch_identity()
.returning(move |_, _| Ok(Some(identity.clone())));
Expand Down Expand Up @@ -421,8 +436,8 @@ mod test {

let mut state_repository_mock = MockStateRepositoryLike::new();
state_repository_mock
.expect_fetch_sml_store()
.returning(move || Ok(sml_store.clone()));
.expect_is_in_the_valid_master_nodes_list()
.returning(move |_| Ok(true));
state_repository_mock
.expect_fetch_identity()
.returning(move |_, _| Ok(Some(identity.clone())));
Expand Down
Loading