From 3077d772197c9cf4fdb71cdbb81502dbbd3c9a26 Mon Sep 17 00:00:00 2001 From: Anton Suprunchuk Date: Tue, 11 Apr 2023 18:39:17 +0700 Subject: [PATCH 1/6] feat(dpp): move all dpp changes from integration branch --- packages/rs-dpp/Cargo.toml | 2 +- .../rs-dpp/src/data_contract/data_contract.rs | 32 ++++++- ...data_contract_update_transition_factory.rs | 2 +- .../data_contract_update_transition/mod.rs | 4 +- .../src/data_trigger/dpns_triggers/mod.rs | 22 ++--- .../feature_flags_data_triggers/mod.rs | 4 +- .../data_trigger/get_data_triggers_factory.rs | 2 +- packages/rs-dpp/src/data_trigger/mod.rs | 4 +- .../reward_share_data_triggers/mod.rs | 84 +++++++++-------- .../rs-dpp/src/document/document_factory.rs | 12 +++ ...lidate_documents_batch_transition_state.rs | 2 +- .../identity_update_transition.rs | 27 ++++-- packages/rs-dpp/src/state_repository.rs | 13 +++ ..._transition_fee_from_operations_factory.rs | 78 +++++++++++++++- .../state_transition_factory.rs | 28 ++++++ .../data_contract_validator_spec.rs | 2 +- .../identity_update_transition_spec.rs | 18 ++-- .../payloads/contract/dashpay-contract.json | 4 +- packages/wasm-dpp/Cargo.toml | 2 + .../lib/test/fixtures/getIdentityFixture.js | 40 +++++---- .../test/fixtures/getInstantLockFixture.js | 53 +++++++++++ packages/wasm-dpp/package.json | 1 + packages/wasm-dpp/scripts/build.sh | 2 +- packages/wasm-dpp/src/buffer.rs | 16 +++- .../wasm-dpp/src/dash_platform_protocol.rs | 4 + .../src/data_contract/data_contract.rs | 17 +++- .../src/data_contract/data_contract_facade.rs | 4 +- .../data_contract_create_transition/mod.rs | 5 ++ .../data_contract_update_transition/mod.rs | 25 +++++- .../src/document/extended_document.rs | 45 +++++++--- packages/wasm-dpp/src/document/mod.rs | 30 +++---- .../document_create_transition.rs | 12 ++- .../document_replace_transition.rs | 6 +- .../document_transition/mod.rs | 32 +++---- .../document_batch_transition/mod.rs | 2 +- .../invalid_identity_public_key_type_error.rs | 13 +++ .../invalid_state_transition_type_error.rs | 7 ++ .../missing_state_transition_type_error.rs | 7 ++ packages/wasm-dpp/src/errors/mod.rs | 2 +- .../generate_temporary_ecdsa_private_key.rs | 19 ++++ .../src/identity/identity_public_key/mod.rs | 18 ++-- packages/wasm-dpp/src/identity/mod.rs | 14 ++- .../identity_public_key_transitions.rs | 4 +- packages/wasm-dpp/src/lib.rs | 1 + packages/wasm-dpp/src/metadata.rs | 2 +- packages/wasm-dpp/src/state_repository.rs | 50 ++++++++++- .../errors/invalid_state_transition_error.rs | 18 +++- .../fee/calculate_operation_fees.rs | 11 +-- ...te_state_transition_fee_from_operations.rs | 29 ++++++ .../wasm-dpp/src/state_transition/fee/mod.rs | 1 + .../operations/pre_calculated_operation.rs | 90 +++++++++++++++++-- .../fee/operations/read_operation.rs | 19 ++++ .../signature_verification_operation.rs | 15 ++++ .../src/state_transition/fee/refunds.rs | 17 ++++ packages/wasm-dpp/src/state_transition/mod.rs | 10 +++ .../state_transition_facade.rs | 24 ++++- packages/wasm-dpp/src/utils.rs | 25 +++++- .../src/validation/validation_result.rs | 35 +++++++- .../dataContract/DataContractFacade.spec.js | 43 ++++++++- .../validateDataContractFactory.spec.js | 4 +- ...entityUpdateTransitionStateFactory.spec.js | 2 +- .../generateTemporaryEcdsaPrivateKey.spec.js | 17 ++++ .../unit/dataContract/DataContract.spec.js | 1 + ...ataContractUpdateTransitionFactory.spec.js | 2 +- .../test/unit/document/Document.spec.js | 20 ++--- .../unit/document/DocumentFactory.spec.js | 2 +- ...plyDocumentsBatchTransitionFactory.spec.js | 2 +- ...cumentsBatchTransitionStateFactory.spec.js | 26 +++--- .../unit/identity/IdentityPublicKey.spec.js | 15 ++-- .../StateTransitionExecutionContext.spec.js | 5 +- .../StateTransitionFactory.spec.js | 3 +- ...TransitionIdentitySignatureFactory.spec.js | 4 +- 72 files changed, 961 insertions(+), 252 deletions(-) create mode 100644 packages/wasm-dpp/lib/test/fixtures/getInstantLockFixture.js create mode 100644 packages/wasm-dpp/src/generate_temporary_ecdsa_private_key.rs create mode 100644 packages/wasm-dpp/src/state_transition/fee/calculate_state_transition_fee_from_operations.rs create mode 100644 packages/wasm-dpp/test/integration/util/generateTemporaryEcdsaPrivateKey.spec.js diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 88fe09e8cde..afbe78c15fc 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -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"] } diff --git a/packages/rs-dpp/src/data_contract/data_contract.rs b/packages/rs-dpp/src/data_contract/data_contract.rs index 508e3283463..67519af342b 100644 --- a/packages/rs-dpp/src/data_contract/data_contract.rs +++ b/packages/rs-dpp/src/data_contract/data_contract.rs @@ -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> { diff --git a/packages/rs-dpp/src/data_contract/state_transition/data_contract_update_transition/apply_data_contract_update_transition_factory.rs b/packages/rs-dpp/src/data_contract/state_transition/data_contract_update_transition/apply_data_contract_update_transition_factory.rs index 035ae0fea67..c496903b3e2 100644 --- a/packages/rs-dpp/src/data_contract/state_transition/data_contract_update_transition/apply_data_contract_update_transition_factory.rs +++ b/packages/rs-dpp/src/data_contract/state_transition/data_contract_update_transition/apply_data_contract_update_transition_factory.rs @@ -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()), ) diff --git a/packages/rs-dpp/src/data_contract/state_transition/data_contract_update_transition/mod.rs b/packages/rs-dpp/src/data_contract/state_transition/data_contract_update_transition/mod.rs index 155f034805f..cc406d9a240 100644 --- a/packages/rs-dpp/src/data_contract/state_transition/data_contract_update_transition/mod.rs +++ b/packages/rs-dpp/src/data_contract/state_transition/data_contract_update_transition/mod.rs @@ -57,8 +57,8 @@ 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)] + // we want to skip serialization of transitions, as we do it manually in `to_object()` and `to_json()` + // #[serde(skip_serializing)] pub data_contract: DataContract, pub signature_public_key_id: KeyID, pub signature: BinaryData, diff --git a/packages/rs-dpp/src/data_trigger/dpns_triggers/mod.rs b/packages/rs-dpp/src/data_trigger/dpns_triggers/mod.rs index 9dbb3da04b1..41e2acb18d8 100644 --- a/packages/rs-dpp/src/data_trigger/dpns_triggers/mod.rs +++ b/packages/rs-dpp/src/data_trigger/dpns_triggers/mod.rs @@ -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, @@ -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()); @@ -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 @@ -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 @@ -139,7 +139,7 @@ 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()) @@ -147,6 +147,8 @@ where } 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(); @@ -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()); @@ -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(), ); @@ -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()); @@ -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()) diff --git a/packages/rs-dpp/src/data_trigger/feature_flags_data_triggers/mod.rs b/packages/rs-dpp/src/data_trigger/feature_flags_data_triggers/mod.rs index eed45ccf499..65ba4b16cd1 100644 --- a/packages/rs-dpp/src/data_trigger/feature_flags_data_triggers/mod.rs +++ b/packages/rs-dpp/src/data_trigger/feature_flags_data_triggers/mod.rs @@ -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()); @@ -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()); diff --git a/packages/rs-dpp/src/data_trigger/get_data_triggers_factory.rs b/packages/rs-dpp/src/data_trigger/get_data_triggers_factory.rs index 87837735cbe..b40bb6f965e 100644 --- a/packages/rs-dpp/src/data_trigger/get_data_triggers_factory.rs +++ b/packages/rs-dpp/src/data_trigger/get_data_triggers_factory.rs @@ -135,7 +135,7 @@ pub fn data_triggers() -> Result, 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(), transition_action: Action::Create, data_trigger_kind: DataTriggerKind::DataTriggerRewardShare, top_level_identity: None, diff --git a/packages/rs-dpp/src/data_trigger/mod.rs b/packages/rs-dpp/src/data_trigger/mod.rs index e7573394ccf..c1abf50f336 100644 --- a/packages/rs-dpp/src/data_trigger/mod.rs +++ b/packages/rs-dpp/src/data_trigger/mod.rs @@ -147,11 +147,11 @@ where fn create_error( context: &DataTriggerExecutionContext, - 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() } diff --git a/packages/rs-dpp/src/data_trigger/reward_share_data_triggers/mod.rs b/packages/rs-dpp/src/data_trigger/reward_share_data_triggers/mod.rs index edf7c094df4..64404534f9c 100644 --- a/packages/rs-dpp/src/data_trigger/reward_share_data_triggers/mod.rs +++ b/packages/rs-dpp/src/data_trigger/reward_share_data_triggers/mod.rs @@ -32,17 +32,24 @@ 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 ) })?; @@ -50,20 +57,25 @@ where 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?; + + // // 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()); @@ -83,19 +95,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), ) @@ -112,7 +125,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 @@ -130,7 +143,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()); @@ -246,6 +259,7 @@ mod test { sml_store, data_contract, top_level_identifier, + identity, .. } = setup_test(); @@ -257,11 +271,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())); @@ -281,7 +295,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() @@ -300,8 +314,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)); @@ -345,8 +359,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)); @@ -385,8 +399,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()))); @@ -421,8 +435,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()))); diff --git a/packages/rs-dpp/src/document/document_factory.rs b/packages/rs-dpp/src/document/document_factory.rs index f86a3fbea4a..475b17012bc 100644 --- a/packages/rs-dpp/src/document/document_factory.rs +++ b/packages/rs-dpp/src/document/document_factory.rs @@ -402,6 +402,18 @@ where let new_revision = document_revision + 1; map.insert(PROPERTY_REVISION.to_string(), Value::U64(new_revision)); + // If document have an originally set `updatedAt` + // we should update it then + let contains_updated_at = document + .document_type()? + .required_fields + .contains(PROPERTY_UPDATED_AT); + + if contains_updated_at { + let now = Utc::now().timestamp_millis() as TimestampMillis; + map.insert(PROPERTY_UPDATED_AT.to_string(), Value::U64(now)); + } + raw_transitions.push(map.into()); } Ok(raw_transitions) diff --git a/packages/rs-dpp/src/document/state_transition/documents_batch_transition/validation/state/validate_documents_batch_transition_state.rs b/packages/rs-dpp/src/document/state_transition/documents_batch_transition/validation/state/validate_documents_batch_transition_state.rs index 5335202ce31..69e963936b9 100644 --- a/packages/rs-dpp/src/document/state_transition/documents_batch_transition/validation/state/validate_documents_batch_transition_state.rs +++ b/packages/rs-dpp/src/document/state_transition/documents_batch_transition/validation/state/validate_documents_batch_transition_state.rs @@ -147,7 +147,7 @@ pub async fn validate_document_transitions( // Data Contract must exist let data_contract = state_repository - .fetch_data_contract(data_contract_id, None) + .fetch_data_contract(data_contract_id, Some(&tmp_execution_context)) .await? .map(TryInto::try_into) .transpose() diff --git a/packages/rs-dpp/src/identity/state_transition/identity_update_transition/identity_update_transition.rs b/packages/rs-dpp/src/identity/state_transition/identity_update_transition/identity_update_transition.rs index 64f3d1fc08c..757a46c79c1 100644 --- a/packages/rs-dpp/src/identity/state_transition/identity_update_transition/identity_update_transition.rs +++ b/packages/rs-dpp/src/identity/state_transition/identity_update_transition/identity_update_transition.rs @@ -58,7 +58,7 @@ pub struct IdentityUpdateTransition { /// Public Keys to add to the Identity /// we want to skip serialization of transitions, as we does it manually in `to_object()` and `to_json()` - #[serde(default)] + #[serde(skip, default)] pub add_public_keys: Vec, /// Identity Public Keys ID's to disable for the Identity @@ -275,10 +275,12 @@ impl StateTransitionConvert for IdentityUpdateTransition { add_public_keys.push(key.to_raw_object(skip_signature)?); } - value.insert( - property_names::ADD_PUBLIC_KEYS.to_owned(), - Value::Array(add_public_keys), - )?; + if !add_public_keys.is_empty() { + value.insert_at_end( + property_names::ADD_PUBLIC_KEYS.to_owned(), + Value::Array(add_public_keys), + )?; + } Ok(value) } @@ -302,13 +304,20 @@ impl StateTransitionConvert for IdentityUpdateTransition { add_public_keys.push(key.to_raw_cleaned_object(skip_signature)?); } - value.insert( - property_names::ADD_PUBLIC_KEYS.to_owned(), - Value::Array(add_public_keys), - )?; + if !add_public_keys.is_empty() { + value.insert_at_end( + property_names::ADD_PUBLIC_KEYS.to_owned(), + Value::Array(add_public_keys), + )?; + } Ok(value) } + + // Override to_canonical_cleaned_object to manage add_public_keys individually + fn to_canonical_cleaned_object(&self, skip_signature: bool) -> Result { + self.to_cleaned_object(skip_signature) + } } impl StateTransitionLike for IdentityUpdateTransition { diff --git a/packages/rs-dpp/src/state_repository.rs b/packages/rs-dpp/src/state_repository.rs index 7472399d3ca..5dedd11599a 100644 --- a/packages/rs-dpp/src/state_repository.rs +++ b/packages/rs-dpp/src/state_repository.rs @@ -54,6 +54,7 @@ pub trait StateRepositoryLike: Sync { execution_context: Option<&'a StateTransitionExecutionContext>, ) -> AnyResult>; + // TODO(wasm-dpp): rename to `create_data_contract` /// Store Data Contract async fn store_data_contract<'a>( &self, @@ -61,6 +62,12 @@ pub trait StateRepositoryLike: Sync { execution_context: Option<&'a StateTransitionExecutionContext>, ) -> AnyResult<()>; + async fn update_data_contract<'a>( + &self, + data_contract: DataContract, + execution_context: Option<&'a StateTransitionExecutionContext>, + ) -> AnyResult<()>; + /// Fetch Documents by Data Contract Id and type /// By default, the method should return data as bytes (`Vec`), but the deserialization to [`Document`] should be also possible async fn fetch_documents<'a>( @@ -225,6 +232,12 @@ pub trait StateRepositoryLike: Sync { where T: for<'de> serde::de::Deserialize<'de> + 'static; + /// Check if AssetLock Transaction outPoint exists in spent list + async fn is_in_the_valid_master_nodes_list( + &self, + out_point_buffer: [u8; 32], + ) -> AnyResult; + // Get latest (in a queue) withdrawal transaction index async fn fetch_latest_withdrawal_transaction_index(&self) -> AnyResult; diff --git a/packages/rs-dpp/src/state_transition/fee/calculate_state_transition_fee_from_operations_factory.rs b/packages/rs-dpp/src/state_transition/fee/calculate_state_transition_fee_from_operations_factory.rs index 89eee9ed9b1..68602c5858f 100644 --- a/packages/rs-dpp/src/state_transition/fee/calculate_state_transition_fee_from_operations_factory.rs +++ b/packages/rs-dpp/src/state_transition/fee/calculate_state_transition_fee_from_operations_factory.rs @@ -40,8 +40,19 @@ fn calculate_state_transition_fee_from_operations_with_custom_calculator( .fold(0, |sum, (_, credits)| sum + credits); } - let required_amount = (storage_fee - total_refunds) + DEFAULT_USER_TIP; - let desired_amount = (storage_fee + processing_fee - total_refunds) + DEFAULT_USER_TIP; + let required_amount = if storage_fee > total_refunds { + (storage_fee - total_refunds) + DEFAULT_USER_TIP + } else { + 0 + }; + + let fee_sum = storage_fee + processing_fee; + + let desired_amount = if fee_sum > total_refunds { + (fee_sum - total_refunds) + DEFAULT_USER_TIP + } else { + 0 + }; Ok(FeeResult { storage_fee, @@ -55,8 +66,15 @@ fn calculate_state_transition_fee_from_operations_with_custom_calculator( #[cfg(test)] mod test { + use dashcore::blockdata::script::Instruction::Op; + use platform_value::Identifier; use std::collections::HashMap; + use crate::identity::KeyType::ECDSA_SECP256K1; + use crate::state_transition::fee::calculate_operation_fees::calculate_operation_fees; + use crate::state_transition::fee::operations::{ + PreCalculatedOperation, SignatureVerificationOperation, + }; use crate::{ state_transition::fee::{ operations::Operation, Credits, DummyFeesResult, FeeResult, Refunds, @@ -109,4 +127,60 @@ mod test { }; assert_eq!(expected, result); } + + // TODO(wasm-dpp): remove this test if we don't need id + #[test] + fn failing_test_with_negative_credits() { + // Set of operations that produced by Document Remove Transition + let operations = vec![ + Operation::PreCalculated(PreCalculatedOperation { + storage_cost: 0, + processing_cost: 551320, + fee_refunds: vec![], + }), + Operation::SignatureVerification(SignatureVerificationOperation { + signature_type: ECDSA_SECP256K1, + }), + Operation::PreCalculated(PreCalculatedOperation { + storage_cost: 0, + processing_cost: 551320, + fee_refunds: vec![], + }), + Operation::PreCalculated(PreCalculatedOperation { + storage_cost: 0, + processing_cost: 191260, + fee_refunds: vec![], + }), + Operation::PreCalculated(PreCalculatedOperation { + storage_cost: 0, + processing_cost: 16870910, + fee_refunds: vec![Refunds { + identifier: Identifier::new([ + 130, 188, 56, 7, 78, 143, 58, 212, 133, 162, 145, 56, 186, 219, 191, 75, + 64, 112, 236, 226, 135, 75, 132, 170, 135, 243, 180, 110, 103, 161, 153, + 252, + ]), + credits_per_epoch: [("0".to_string(), 114301030)].iter().cloned().collect(), + }], + }), + ]; + + let identifier = Identifier::new([ + 130, 188, 56, 7, 78, 143, 58, 212, 133, 162, 145, 56, 186, 219, 191, 75, 64, 112, 236, + 226, 135, 75, 132, 170, 135, 243, 180, 110, 103, 161, 153, 252, + ]); + + // Panics because of negative credits + let result = calculate_state_transition_fee_from_operations_with_custom_calculator( + &operations, + &identifier, + calculate_operation_fees, + ); + + assert!(matches!(result, Ok(FeeResult { + desired_amount, + required_amount, + .. + }) if desired_amount == 0 && required_amount == 0)); + } } diff --git a/packages/rs-dpp/src/state_transition/state_transition_factory.rs b/packages/rs-dpp/src/state_transition/state_transition_factory.rs index 2c859f1c5a4..f57f120034d 100644 --- a/packages/rs-dpp/src/state_transition/state_transition_factory.rs +++ b/packages/rs-dpp/src/state_transition/state_transition_factory.rs @@ -133,6 +133,34 @@ where } }; + let maybe_transition_type = raw_state_transition.get_optional_integer::("type")?; + + // When converting to buffer and back, for the update identity transition + // the type information about identifiers is going to be lost. In order + // to fix it, we need to call clean_value on it. + if let Some(transition_type_int) = maybe_transition_type { + let state_transition_type = StateTransitionType::try_from(transition_type_int) + .map_err(|_| StateTransitionError::InvalidStateTransitionError { + errors: vec![ConsensusError::from(InvalidStateTransitionTypeError::new( + transition_type_int, + ))], + raw_state_transition: raw_state_transition.clone(), + })?; + + match state_transition_type { + StateTransitionType::DataContractUpdate => { + DataContractUpdateTransition::clean_value(&mut raw_state_transition)?; + } + _ => {} + } + } else { + return Err(StateTransitionError::InvalidStateTransitionError { + errors: vec![ConsensusError::from(MissingStateTransitionTypeError::new())], + raw_state_transition, + } + .into()); + } + self.create_from_object(raw_state_transition, options).await } } diff --git a/packages/rs-dpp/src/tests/data_contract/validation/data_contract_validator_spec.rs b/packages/rs-dpp/src/tests/data_contract/validation/data_contract_validator_spec.rs index 10f070b45b5..829b2572cd4 100644 --- a/packages/rs-dpp/src/tests/data_contract/validation/data_contract_validator_spec.rs +++ b/packages/rs-dpp/src/tests/data_contract/validation/data_contract_validator_spec.rs @@ -1320,7 +1320,7 @@ mod documents { "properties": { "something": { "type": "string", - "format": "url", + "format": "uri", "maxLength": 60000, }, }, diff --git a/packages/rs-dpp/src/tests/identity/state_transition/identity_update_transition/identity_update_transition_spec.rs b/packages/rs-dpp/src/tests/identity/state_transition/identity_update_transition/identity_update_transition_spec.rs index 88388c15884..aab679bd883 100644 --- a/packages/rs-dpp/src/tests/identity/state_transition/identity_update_transition/identity_update_transition_spec.rs +++ b/packages/rs-dpp/src/tests/identity/state_transition/identity_update_transition/identity_update_transition_spec.rs @@ -141,6 +141,8 @@ fn to_object() { "signaturePublicKeyId": 0u32, "identityId" : transition.identity_id, "revision": 0 as Revision, + "disablePublicKeys" : [0u32], + "publicKeysDisabledAt" : 1234567u64, "addPublicKeys" : [ { @@ -152,9 +154,7 @@ fn to_object() { "readOnly" : false, "signature" : BinaryData::new(vec![0u8;65]) } - ], - "disablePublicKeys" : [0u32], - "publicKeysDisabledAt" : 1234567u64, + ] }); assert_eq!(expected_raw_state_transition, result); @@ -172,6 +172,8 @@ fn to_object_with_signature_skipped() { "type" : 5u8, "identityId" : transition.identity_id, "revision": 0 as Revision, + "disablePublicKeys" : [0u32], + "publicKeysDisabledAt" : 1234567u64, "addPublicKeys" : [ { @@ -182,9 +184,7 @@ fn to_object_with_signature_skipped() { "data" :BinaryData::new(base64::decode("AkVuTKyF3YgKLAQlLEtaUL2HTditwGILfWUVqjzYnIgH").unwrap()), "readOnly" : false, } - ], - "disablePublicKeys" : [0u32], - "publicKeysDisabledAt" : 1234567u64, + ] }); assert_eq!(expected_raw_state_transition, result); @@ -204,6 +204,8 @@ fn to_json() { "signaturePublicKeyId": 0u32, "identityId" : transition.identity_id, "revision": 0 as Revision, + "disablePublicKeys" : [0u32], + "publicKeysDisabledAt" : 1234567u64, "addPublicKeys" : [ { @@ -215,9 +217,7 @@ fn to_json() { "readOnly" : false, "signature" : BinaryData::new(vec![0;65]), } - ], - "disablePublicKeys" : [0u32], - "publicKeysDisabledAt" : 1234567u64, + ] }); assert_eq!(expected_raw_state_transition, result); diff --git a/packages/rs-dpp/src/tests/payloads/contract/dashpay-contract.json b/packages/rs-dpp/src/tests/payloads/contract/dashpay-contract.json index 73006b86f0d..ab23fc63ffb 100644 --- a/packages/rs-dpp/src/tests/payloads/contract/dashpay-contract.json +++ b/packages/rs-dpp/src/tests/payloads/contract/dashpay-contract.json @@ -28,7 +28,7 @@ "properties": { "avatarUrl": { "type": "string", - "format": "url", + "format": "uri", "maxLength": 2048 }, "publicMessage": { @@ -192,4 +192,4 @@ "additionalProperties": false } } -} \ No newline at end of file +} diff --git a/packages/wasm-dpp/Cargo.toml b/packages/wasm-dpp/Cargo.toml index c58f8352690..65cf0c094a3 100644 --- a/packages/wasm-dpp/Cargo.toml +++ b/packages/wasm-dpp/Cargo.toml @@ -18,6 +18,8 @@ serde-wasm-bindgen = { git="https://github.com/QuantumExplorer/serde-wasm-bindge dpp = { path = "../rs-dpp", default-features = false } itertools = { version="0.10.5"} console_error_panic_hook = { version="0.1.7"} +log = { version = "0.4.6" } +wasm-logger = { version = "0.2.0" } wasm-bindgen-futures = "0.4.33" async-trait = "0.1.59" diff --git a/packages/wasm-dpp/lib/test/fixtures/getIdentityFixture.js b/packages/wasm-dpp/lib/test/fixtures/getIdentityFixture.js index b1029f6f74d..5af5cbad60c 100644 --- a/packages/wasm-dpp/lib/test/fixtures/getIdentityFixture.js +++ b/packages/wasm-dpp/lib/test/fixtures/getIdentityFixture.js @@ -7,7 +7,7 @@ let staticId = null; /** * @return {Identity} */ -module.exports = async function getIdentityFixture(id = staticId) { +module.exports = async function getIdentityFixture(id = staticId, publicKeys = undefined) { ({ Identity, IdentityPublicKey } = await loadWasmDpp()); if (!staticId) { @@ -19,30 +19,32 @@ module.exports = async function getIdentityFixture(id = staticId) { id = staticId; } + const preCreatedPublicKeys = [ + { + id: 0, + type: IdentityPublicKey.TYPES.ECDSA_SECP256K1, + data: Buffer.from('AuryIuMtRrl/VviQuyLD1l4nmxi9ogPzC9LT7tdpo0di', 'base64'), + purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, + securityLevel: IdentityPublicKey.SECURITY_LEVELS.MASTER, + readOnly: false, + }, + { + id: 1, + type: IdentityPublicKey.TYPES.ECDSA_SECP256K1, + data: Buffer.from('A8AK95PYMVX5VQKzOhcVQRCUbc9pyg3RiL7jttEMDU+L', 'base64'), + purpose: IdentityPublicKey.PURPOSES.ENCRYPTION, + securityLevel: IdentityPublicKey.SECURITY_LEVELS.MEDIUM, + readOnly: false, + }, + ]; + const rawIdentity = { // TODO: obtain latest version from some wasm binding? protocolVersion: 1, id, // TODO: should be probably id.toBuffer(), but it causes panic in IdentityWasm balance: 10, revision: 0, - publicKeys: [ - { - id: 0, - type: IdentityPublicKey.TYPES.ECDSA_SECP256K1, - data: Buffer.from('AuryIuMtRrl/VviQuyLD1l4nmxi9ogPzC9LT7tdpo0di', 'base64'), - purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, - securityLevel: IdentityPublicKey.SECURITY_LEVELS.MASTER, - readOnly: false, - }, - { - id: 1, - type: IdentityPublicKey.TYPES.ECDSA_SECP256K1, - data: Buffer.from('A8AK95PYMVX5VQKzOhcVQRCUbc9pyg3RiL7jttEMDU+L', 'base64'), - purpose: IdentityPublicKey.PURPOSES.ENCRYPTION, - securityLevel: IdentityPublicKey.SECURITY_LEVELS.MEDIUM, - readOnly: false, - }, - ], + publicKeys: publicKeys === undefined ? preCreatedPublicKeys : publicKeys, }; return new Identity(rawIdentity); diff --git a/packages/wasm-dpp/lib/test/fixtures/getInstantLockFixture.js b/packages/wasm-dpp/lib/test/fixtures/getInstantLockFixture.js new file mode 100644 index 00000000000..ec26db769bc --- /dev/null +++ b/packages/wasm-dpp/lib/test/fixtures/getInstantLockFixture.js @@ -0,0 +1,53 @@ +const { + Transaction, + InstantLock, + PrivateKey, + Script, + Opcode, +} = require('@dashevo/dashcore-lib'); + +/** + * @param {PrivateKey} [oneTimePrivateKey] + */ +function getInstantLockFixture(oneTimePrivateKey = new PrivateKey()) { + const privateKeyHex = 'cSBnVM4xvxarwGQuAfQFwqDg9k5tErHUHzgWsEfD4zdwUasvqRVY'; + const privateKey = new PrivateKey(privateKeyHex); + const fromAddress = privateKey.toAddress(); + + const oneTimePublicKey = oneTimePrivateKey.toPublicKey(); + + const transaction = new Transaction() + .from({ + address: fromAddress, + txId: 'a477af6b2667c29670467e4e0728b685ee07b240235771862318e29ddbe58458', + outputIndex: 0, + script: Script.buildPublicKeyHashOut(fromAddress) + .toString(), + satoshis: 100000, + }) + // eslint-disable-next-line no-underscore-dangle + .addBurnOutput(90000, oneTimePublicKey._getID()) + .to(fromAddress, 5000) + .addOutput(Transaction.Output({ + satoshis: 5000, + script: Script() + .add(Opcode.OP_RETURN) + .add(Buffer.from([1, 2, 3])), + })) + .sign(privateKey); + + return new InstantLock({ + version: 1, + inputs: [ + { + outpointHash: '6e200d059fb567ba19e92f5c2dcd3dde522fd4e0a50af223752db16158dabb1d', + outpointIndex: 0, + }, + ], + txid: transaction.id, + cyclehash: '7c30826123d0f29fe4c4a8895d7ba4eb469b1fafa6ad7b23896a1a591766a536', + signature: '8967c46529a967b3822e1ba8a173066296d02593f0f59b3a78a30a7eef9c8a120847729e62e4a32954339286b79fe7590221331cd28d576887a263f45b595d499272f656c3f5176987c976239cac16f972d796ad82931d532102a4f95eec7d80', + }); +} + +module.exports = getInstantLockFixture; diff --git a/packages/wasm-dpp/package.json b/packages/wasm-dpp/package.json index b3e998f386b..3d94f00fd43 100644 --- a/packages/wasm-dpp/package.json +++ b/packages/wasm-dpp/package.json @@ -9,6 +9,7 @@ "test": "yarn run test:node && yarn run test:browsers", "test:browsers": "karma start ./karma.conf.js --single-run", "test:node": "NODE_ENV=test mocha", + "tsc": "tsc", "lint": "eslint .", "lint:fix": "eslint . --fix", "clean": "yarn exec scripts/clean.sh" diff --git a/packages/wasm-dpp/scripts/build.sh b/packages/wasm-dpp/scripts/build.sh index cab572ac793..ec83e49c0e9 100755 --- a/packages/wasm-dpp/scripts/build.sh +++ b/packages/wasm-dpp/scripts/build.sh @@ -18,7 +18,7 @@ fi OUTPUT_DIR="$PWD/wasm" OUTPUT_FILE="$OUTPUT_DIR/wasm_dpp_bg.wasm" OUTPUT_FILE_JS="$OUTPUT_DIR/wasm_dpp_bg.js" -BUILD_COMMAND="cargo build --target=$TARGET $PROFILE_ARG" +BUILD_COMMAND="cargo build --config net.git-fetch-with-cli=true --target=$TARGET $PROFILE_ARG" BINDGEN_COMMAND="wasm-bindgen --out-dir=$OUTPUT_DIR --target=web --omit-default-module-path ../../target/$TARGET/$PROFILE/wasm_dpp.wasm" DIST_TYPINGS="$PWD/dist/wasm/wasm_dpp.d.ts" diff --git a/packages/wasm-dpp/src/buffer.rs b/packages/wasm-dpp/src/buffer.rs index c0b6db19c9f..efae80aaccc 100644 --- a/packages/wasm-dpp/src/buffer.rs +++ b/packages/wasm-dpp/src/buffer.rs @@ -1,3 +1,4 @@ +use js_sys::ArrayBuffer; use wasm_bindgen::prelude::*; #[wasm_bindgen] @@ -7,12 +8,21 @@ extern "C" { #[wasm_bindgen(constructor)] pub fn new() -> Buffer; - #[wasm_bindgen(constructor, js_name = "from")] + #[wasm_bindgen(static_method_of = Buffer, js_name = from)] pub fn from_bytes(js_sys: &[u8]) -> Buffer; - #[wasm_bindgen(constructor, js_name = "from")] + #[wasm_bindgen(static_method_of = Buffer, js_name = from)] pub fn from_bytes_owned(js_sys: Vec) -> Buffer; - #[wasm_bindgen(constructor, js_name = "from")] + #[wasm_bindgen(static_method_of = Buffer, js_name = from)] pub fn from_string(js_sys: String) -> Buffer; + + #[wasm_bindgen(method, getter)] + pub fn buffer(this: &Buffer) -> ArrayBuffer; + + #[wasm_bindgen(method, getter, js_name = byteOffset)] + pub fn byte_offset(this: &Buffer) -> u32; + + #[wasm_bindgen(method, getter)] + pub fn length(this: &Buffer) -> u32; } diff --git a/packages/wasm-dpp/src/dash_platform_protocol.rs b/packages/wasm-dpp/src/dash_platform_protocol.rs index c92ace32451..aeed22ba06d 100644 --- a/packages/wasm-dpp/src/dash_platform_protocol.rs +++ b/packages/wasm-dpp/src/dash_platform_protocol.rs @@ -45,6 +45,10 @@ impl DashPlatformProtocol { entropy_generator: ExternalEntropyGenerator, maybe_protocol_version: Option, ) -> Result { + if cfg!(debug_assertions) { + wasm_logger::init(wasm_logger::Config::new(log::Level::Debug)); + } + let bls = BlsAdapter(bls_adapter); let protocol_version = maybe_protocol_version.unwrap_or(LATEST_VERSION); let public_keys_validator = Arc::new(PublicKeysValidator::new(bls.clone()).unwrap()); diff --git a/packages/wasm-dpp/src/data_contract/data_contract.rs b/packages/wasm-dpp/src/data_contract/data_contract.rs index fd22177cfa1..ffa07d015e0 100644 --- a/packages/wasm-dpp/src/data_contract/data_contract.rs +++ b/packages/wasm-dpp/src/data_contract/data_contract.rs @@ -16,7 +16,7 @@ use dpp::{platform_value, Convertible}; use crate::errors::RustConversionError; use crate::identifier::identifier_from_js_value; use crate::metadata::MetadataWasm; -use crate::utils::WithJsError; +use crate::utils::{IntoWasm, WithJsError}; use crate::{bail_js, with_js_error}; use crate::{buffer::Buffer, identifier::IdentifierWrapper}; @@ -181,7 +181,9 @@ impl DataContractWasm { schema: JsValue, ) -> Result<(), JsValue> { let json_schema: JsonValue = with_js_error!(serde_wasm_bindgen::from_value(schema))?; - self.0.set_document_schema(doc_type, json_schema); + self.0 + .set_document_schema(doc_type, json_schema) + .with_js_error()?; Ok(()) } @@ -260,8 +262,15 @@ impl DataContractWasm { } #[wasm_bindgen(js_name=setMetadata)] - pub fn set_metadata(&mut self, metadata: MetadataWasm) { - self.0.metadata = Some(metadata.into()); + pub fn set_metadata(&mut self, metadata: JsValue) -> Result<(), JsValue> { + self.0.metadata = if !metadata.is_falsy() { + let metadata = metadata.to_wasm::("Metadata")?; + Some(metadata.to_owned().into()) + } else { + None + }; + + Ok(()) } #[wasm_bindgen(js_name=toObject)] diff --git a/packages/wasm-dpp/src/data_contract/data_contract_facade.rs b/packages/wasm-dpp/src/data_contract/data_contract_facade.rs index 11227b95e86..3e7563a32e9 100644 --- a/packages/wasm-dpp/src/data_contract/data_contract_facade.rs +++ b/packages/wasm-dpp/src/data_contract/data_contract_facade.rs @@ -119,10 +119,10 @@ impl DataContractFacadeWasm { #[wasm_bindgen(js_name=createDataContractUpdateTransition)] pub fn create_data_contract_update_transition( &self, - data_contract: DataContractWasm, + data_contract: &DataContractWasm, ) -> Result { self.0 - .create_data_contract_update_transition(data_contract.into()) + .create_data_contract_update_transition(data_contract.to_owned().into()) .map(Into::into) .map_err(from_protocol_error) } diff --git a/packages/wasm-dpp/src/data_contract/state_transition/data_contract_create_transition/mod.rs b/packages/wasm-dpp/src/data_contract/state_transition/data_contract_create_transition/mod.rs index 73f3b24ad87..b182d63ba34 100644 --- a/packages/wasm-dpp/src/data_contract/state_transition/data_contract_create_transition/mod.rs +++ b/packages/wasm-dpp/src/data_contract/state_transition/data_contract_create_transition/mod.rs @@ -144,6 +144,11 @@ impl DataContractCreateTransitionWasm { self.0.set_execution_context(context.into()) } + #[wasm_bindgen(js_name=getExecutionContext)] + pub fn get_execution_context(&mut self) -> StateTransitionExecutionContextWasm { + self.0.get_execution_context().into() + } + #[wasm_bindgen(js_name=toObject)] pub fn to_object(&self, skip_signature: Option) -> Result { let serde_object = self diff --git a/packages/wasm-dpp/src/data_contract/state_transition/data_contract_update_transition/mod.rs b/packages/wasm-dpp/src/data_contract/state_transition/data_contract_update_transition/mod.rs index 585e043e75e..36696cafe99 100644 --- a/packages/wasm-dpp/src/data_contract/state_transition/data_contract_update_transition/mod.rs +++ b/packages/wasm-dpp/src/data_contract/state_transition/data_contract_update_transition/mod.rs @@ -148,6 +148,11 @@ impl DataContractUpdateTransitionWasm { self.0.set_execution_context(context.into()) } + #[wasm_bindgen(js_name=getExecutionContext)] + pub fn get_execution_context(&mut self) -> StateTransitionExecutionContextWasm { + self.0.get_execution_context().into() + } + #[wasm_bindgen(js_name=hash)] pub fn hash(&self, skip_signature: Option) -> Result { let bytes = self @@ -161,13 +166,31 @@ impl DataContractUpdateTransitionWasm { pub fn to_object(&self, skip_signature: Option) -> Result { let serde_object = self .0 - .to_object(skip_signature.unwrap_or(false)) + .to_cleaned_object(skip_signature.unwrap_or(false)) .map_err(from_protocol_error)?; serde_object .serialize(&serde_wasm_bindgen::Serializer::json_compatible()) .map_err(|e| e.into()) } + #[wasm_bindgen] + pub fn sign( + &mut self, + identity_public_key: &IdentityPublicKeyWasm, + private_key: Vec, + bls: JsBlsAdapter, + ) -> Result<(), JsValue> { + let bls_adapter = BlsAdapter(bls); + + self.0 + .sign( + &identity_public_key.to_owned().into(), + &private_key, + &bls_adapter, + ) + .with_js_error() + } + #[wasm_bindgen(js_name=verifySignature)] pub fn verify_signature( &self, diff --git a/packages/wasm-dpp/src/document/extended_document.rs b/packages/wasm-dpp/src/document/extended_document.rs index cfdf286fbc6..29c535bb6b1 100644 --- a/packages/wasm-dpp/src/document/extended_document.rs +++ b/packages/wasm-dpp/src/document/extended_document.rs @@ -2,7 +2,7 @@ use dpp::document::document_transition::document_base_transition::JsonValue; use dpp::document::{ExtendedDocument, EXTENDED_DOCUMENT_IDENTIFIER_FIELDS}; use dpp::platform_value::{Bytes32, Value}; -use dpp::prelude::{Identifier, Revision}; +use dpp::prelude::{Identifier, Revision, TimestampMillis}; use dpp::util::json_schema::JsonSchemaExt; use dpp::util::json_value::JsonValueExt; @@ -17,7 +17,7 @@ use crate::document::BinaryType; use crate::errors::RustConversionError; use crate::identifier::{identifier_from_js_value, IdentifierWrapper}; use crate::lodash::lodash_set; -use crate::utils::{with_serde_to_platform_value, ToSerdeJSONExt, WithJsError}; +use crate::utils::{with_serde_to_platform_value, IntoWasm, ToSerdeJSONExt, WithJsError}; use crate::{with_js_error, ConversionOptions, DocumentWasm}; use crate::{DataContractWasm, MetadataWasm}; @@ -217,23 +217,37 @@ impl ExtendedDocumentWasm { } #[wasm_bindgen(js_name=setCreatedAt)] - pub fn set_created_at(&mut self, ts: f64) { - self.0.document.created_at = Some(ts as u64); + pub fn set_created_at(&mut self, ts: Option) { + if let Some(ts) = ts { + self.0.document.created_at = Some(ts.get_time() as TimestampMillis); + } else { + self.0.document.created_at = None; + } } #[wasm_bindgen(js_name=setUpdatedAt)] - pub fn set_updated_at(&mut self, ts: f64) { - self.0.document.updated_at = Some(ts as u64); + pub fn set_updated_at(&mut self, ts: Option) { + if let Some(ts) = ts { + self.0.document.updated_at = Some(ts.get_time() as TimestampMillis); + } else { + self.0.document.updated_at = None; + } } #[wasm_bindgen(js_name=getCreatedAt)] - pub fn get_created_at(&self) -> Option { - self.0.document.created_at.map(|v| v as f64) + pub fn get_created_at(&self) -> Option { + self.0 + .document + .created_at + .map(|v| js_sys::Date::new(&JsValue::from_f64(v as f64))) } #[wasm_bindgen(js_name=getUpdatedAt)] - pub fn get_updated_at(&self) -> Option { - self.0.document.updated_at.map(|v| v as f64) + pub fn get_updated_at(&self) -> Option { + self.0 + .document + .updated_at + .map(|v| js_sys::Date::new(&JsValue::from_f64(v as f64))) } #[wasm_bindgen(js_name=getMetadata)] @@ -242,8 +256,15 @@ impl ExtendedDocumentWasm { } #[wasm_bindgen(js_name=setMetadata)] - pub fn set_metadata(&mut self, metadata: &MetadataWasm) { - self.0.metadata = Some(metadata.to_owned().into()); + pub fn set_metadata(&mut self, metadata: JsValue) -> Result<(), JsValue> { + self.0.metadata = if !metadata.is_falsy() { + let metadata = metadata.to_wasm::("Metadata")?; + Some(metadata.to_owned().into()) + } else { + None + }; + + Ok(()) } #[wasm_bindgen(js_name=toObject)] diff --git a/packages/wasm-dpp/src/document/mod.rs b/packages/wasm-dpp/src/document/mod.rs index 5201d9d306f..ccb969231db 100644 --- a/packages/wasm-dpp/src/document/mod.rs +++ b/packages/wasm-dpp/src/document/mod.rs @@ -33,6 +33,7 @@ use dpp::document::{Document, EXTENDED_DOCUMENT_IDENTIFIER_FIELDS, IDENTIFIER_FI pub use extended_document::ExtendedDocumentWasm; use dpp::document::extended_document::property_names; +use dpp::identity::TimestampMillis; use dpp::platform_value::btreemap_extensions::BTreeValueMapReplacementPathHelper; use dpp::platform_value::converter::serde_json::BTreeValueJsonConverter; use dpp::platform_value::ReplacementType; @@ -194,32 +195,27 @@ impl DocumentWasm { } #[wasm_bindgen(js_name=setCreatedAt)] - pub fn set_created_at(&mut self, number: JsValue) -> Result<(), JsValue> { - let ts = try_to_u64(number) - .context("setting createdAt in Document") - .with_js_error()?; - - self.0.created_at = Some(ts); - Ok(()) + pub fn set_created_at(&mut self, created_at: Option) { + self.0.created_at = created_at.map(|timestamp| timestamp.get_time() as TimestampMillis); } #[wasm_bindgen(js_name=setUpdatedAt)] - pub fn set_updated_at(&mut self, number: JsValue) -> Result<(), JsValue> { - let ts = try_to_u64(number) - .context("setting updatedAt in Document") - .with_js_error()?; - self.0.updated_at = Some(ts); - Ok(()) + pub fn set_updated_at(&mut self, updated_at: Option) { + self.0.updated_at = updated_at.map(|timestamp| timestamp.get_time() as TimestampMillis); } #[wasm_bindgen(js_name=getCreatedAt)] - pub fn get_created_at(&self) -> Option { - self.0.created_at.map(|v| v as f64) + pub fn get_created_at(&self) -> Option { + self.0 + .created_at + .map(|v| js_sys::Date::new(&JsValue::from_f64(v as f64))) } #[wasm_bindgen(js_name=getUpdatedAt)] - pub fn get_updated_at(&self) -> Option { - self.0.updated_at.map(|v| v as f64) + pub fn get_updated_at(&self) -> Option { + self.0 + .updated_at + .map(|v| js_sys::Date::new(&JsValue::from_f64(v as f64))) } #[wasm_bindgen(js_name=toObject)] diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_create_transition.rs b/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_create_transition.rs index 33d6584ba7d..c5f0c771f2f 100644 --- a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_create_transition.rs +++ b/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_create_transition.rs @@ -81,13 +81,17 @@ impl DocumentCreateTransitionWasm { } #[wasm_bindgen(js_name=getCreatedAt)] - pub fn created_at(&self) -> Option { - self.inner.created_at + pub fn created_at(&self) -> Option { + self.inner + .created_at + .map(|timestamp| js_sys::Date::new(&JsValue::from_f64(timestamp as f64))) } #[wasm_bindgen(js_name=getUpdatedAt)] - pub fn updated_at(&self) -> Option { - self.inner.updated_at + pub fn updated_at(&self) -> Option { + self.inner + .updated_at + .map(|timestamp| js_sys::Date::new(&JsValue::from_f64(timestamp as f64))) } #[wasm_bindgen(js_name=getRevision)] diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_replace_transition.rs b/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_replace_transition.rs index 051c616ab06..49dda970b4c 100644 --- a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_replace_transition.rs +++ b/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/document_replace_transition.rs @@ -84,8 +84,10 @@ impl DocumentReplaceTransitionWasm { } #[wasm_bindgen(js_name=getUpdatedAt)] - pub fn updated_at(&self) -> Option { - self.inner.updated_at + pub fn updated_at(&self) -> Option { + self.inner + .updated_at + .map(|timestamp| js_sys::Date::new(&JsValue::from_f64(timestamp as f64))) } #[wasm_bindgen(js_name=toObject)] diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/mod.rs b/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/mod.rs index e5fc1b79795..3a983bd9140 100644 --- a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/mod.rs +++ b/packages/wasm-dpp/src/document/state_transition/document_batch_transition/document_transition/mod.rs @@ -8,6 +8,7 @@ pub use document_delete_transition::*; pub use document_replace_transition::*; use dpp::platform_value::Value; +use dpp::prelude::TimestampMillis; use dpp::{ document::document_transition::{ DocumentCreateTransition, DocumentDeleteTransition, DocumentReplaceTransition, @@ -79,46 +80,33 @@ impl DocumentTransitionWasm { #[wasm_bindgen(js_name=getCreatedAt)] pub fn get_created_at(&self) -> JsValue { if let Some(created_at) = self.0.get_created_at() { - (created_at as f64).into() + js_sys::Date::new(&JsValue::from_f64(created_at as f64)).into() } else { JsValue::NULL } } + #[wasm_bindgen(js_name=getUpdatedAt)] pub fn get_updated_at(&self) -> JsValue { if let Some(updated_at) = self.0.get_updated_at() { - (updated_at as f64).into() + js_sys::Date::new(&JsValue::from_f64(updated_at as f64)).into() } else { JsValue::NULL } } #[wasm_bindgen(js_name=setUpdatedAt)] - pub fn set_updated_at(&mut self, js_timestamp_millis: JsValue) -> Result<(), JsValue> { - if js_timestamp_millis.is_undefined() || js_timestamp_millis.is_null() { - self.0.set_updated_at(None); - return Ok(()); - } - let timestamp_millis = try_to_u64(js_timestamp_millis) - .context("setting updatedAt in DocumentsBatchTransition") - .with_js_error()?; - self.0.set_updated_at(Some(timestamp_millis)); + pub fn set_updated_at(&mut self, updated_at: Option) -> Result<(), JsValue> { + self.0 + .set_updated_at(updated_at.map(|timestamp| timestamp.get_time() as TimestampMillis)); Ok(()) } #[wasm_bindgen(js_name=setCreatedAt)] - pub fn set_created_at(&mut self, js_timestamp_millis: JsValue) -> Result<(), JsValue> { - if js_timestamp_millis.is_undefined() || js_timestamp_millis.is_null() { - self.0.set_created_at(None); - return Ok(()); - } - let timestamp_millis = try_to_u64(js_timestamp_millis) - .context("setting createdAt in DocumentsBatchTransition") - .with_js_error()?; - self.0.set_created_at(Some(timestamp_millis)); - - Ok(()) + pub fn set_created_at(&mut self, created_at: Option) { + self.0 + .set_created_at(created_at.map(|timestamp| timestamp.get_time() as TimestampMillis)); } #[wasm_bindgen(js_name=getData)] diff --git a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/mod.rs b/packages/wasm-dpp/src/document/state_transition/document_batch_transition/mod.rs index b0ee1bd0ae4..a65f4692986 100644 --- a/packages/wasm-dpp/src/document/state_transition/document_batch_transition/mod.rs +++ b/packages/wasm-dpp/src/document/state_transition/document_batch_transition/mod.rs @@ -363,7 +363,7 @@ impl DocumentsBatchTransitionWasm { } #[wasm_bindgen(js_name=setExecutionContext)] - pub fn set_execution_context(&mut self, context: StateTransitionExecutionContextWasm) { + pub fn set_execution_context(&mut self, context: &StateTransitionExecutionContextWasm) { self.0.set_execution_context(context.into()) } diff --git a/packages/wasm-dpp/src/errors/consensus/basic/identity/invalid_identity_public_key_type_error.rs b/packages/wasm-dpp/src/errors/consensus/basic/identity/invalid_identity_public_key_type_error.rs index 1fe0755ae78..9e623178ead 100644 --- a/packages/wasm-dpp/src/errors/consensus/basic/identity/invalid_identity_public_key_type_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/basic/identity/invalid_identity_public_key_type_error.rs @@ -1,7 +1,11 @@ +use std::convert::TryFrom; + use crate::buffer::Buffer; +use crate::utils::WithJsError; use dpp::consensus::codes::ErrorWithCode; use dpp::consensus::signature::InvalidIdentityPublicKeyTypeError; use dpp::consensus::ConsensusError; +use dpp::identity::KeyType; use wasm_bindgen::prelude::*; #[wasm_bindgen(js_name=InvalidIdentityPublicKeyTypeError)] @@ -17,6 +21,15 @@ impl From<&InvalidIdentityPublicKeyTypeError> for InvalidIdentityPublicKeyTypeEr #[wasm_bindgen(js_class=InvalidIdentityPublicKeyTypeError)] impl InvalidIdentityPublicKeyTypeErrorWasm { + #[wasm_bindgen(constructor)] + pub fn new(key_type: u8) -> Result { + Ok(Self { + inner: InvalidIdentityPublicKeyTypeError::new( + KeyType::try_from(key_type).with_js_error()?, + ), + }) + } + #[wasm_bindgen(js_name=getPublicKeyType)] pub fn get_public_key_type(&self) -> u8 { self.inner.public_key_type() as u8 diff --git a/packages/wasm-dpp/src/errors/consensus/basic/state_transition/invalid_state_transition_type_error.rs b/packages/wasm-dpp/src/errors/consensus/basic/state_transition/invalid_state_transition_type_error.rs index a2deaa122a3..c55cb460d56 100644 --- a/packages/wasm-dpp/src/errors/consensus/basic/state_transition/invalid_state_transition_type_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/basic/state_transition/invalid_state_transition_type_error.rs @@ -17,6 +17,13 @@ impl From<&InvalidStateTransitionTypeError> for InvalidStateTransitionTypeErrorW #[wasm_bindgen(js_class=InvalidStateTransitionTypeError)] impl InvalidStateTransitionTypeErrorWasm { + #[wasm_bindgen(constructor)] + pub fn new(transition_type: u8) -> Self { + Self { + inner: InvalidStateTransitionTypeError::new(transition_type), + } + } + #[wasm_bindgen(js_name=getType)] pub fn get_type(&self) -> u8 { self.inner.transition_type() diff --git a/packages/wasm-dpp/src/errors/consensus/basic/state_transition/missing_state_transition_type_error.rs b/packages/wasm-dpp/src/errors/consensus/basic/state_transition/missing_state_transition_type_error.rs index caeebd8acdb..94251e6eae7 100644 --- a/packages/wasm-dpp/src/errors/consensus/basic/state_transition/missing_state_transition_type_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/basic/state_transition/missing_state_transition_type_error.rs @@ -17,6 +17,13 @@ impl From<&MissingStateTransitionTypeError> for MissingStateTransitionTypeErrorW #[wasm_bindgen(js_class=MissingStateTransitionTypeError)] impl MissingStateTransitionTypeErrorWasm { + #[wasm_bindgen(constructor)] + pub fn new() -> Self { + Self { + inner: MissingStateTransitionTypeError::new(), + } + } + #[wasm_bindgen(js_name=getCode)] pub fn get_code(&self) -> u32 { ConsensusError::from(self.inner.clone()).code() diff --git a/packages/wasm-dpp/src/errors/mod.rs b/packages/wasm-dpp/src/errors/mod.rs index fd8e6193505..9e517961adf 100644 --- a/packages/wasm-dpp/src/errors/mod.rs +++ b/packages/wasm-dpp/src/errors/mod.rs @@ -13,5 +13,5 @@ pub use public_key_validation_error::*; mod compatible_protocol_version_is_not_defined_error; pub mod data_contract_not_present_error; pub mod dpp_error; -mod value_error; +pub mod value_error; pub use compatible_protocol_version_is_not_defined_error::*; diff --git a/packages/wasm-dpp/src/generate_temporary_ecdsa_private_key.rs b/packages/wasm-dpp/src/generate_temporary_ecdsa_private_key.rs new file mode 100644 index 00000000000..2fa33a91d21 --- /dev/null +++ b/packages/wasm-dpp/src/generate_temporary_ecdsa_private_key.rs @@ -0,0 +1,19 @@ +use crate::buffer::Buffer; +use dpp::dashcore::secp256k1::rand::thread_rng; +use dpp::dashcore::secp256k1::Secp256k1; +use dpp::dashcore::{ + secp256k1::SecretKey, InstantLock, Network, OutPoint, PrivateKey, Script, Transaction, TxIn, + TxOut, Txid, +}; +use wasm_bindgen::prelude::wasm_bindgen; +use wasm_bindgen::JsValue; + +#[wasm_bindgen(js_name = generateTemporaryEcdsaPrivateKey)] +pub fn generate_temporary_ecdsa_private_key() -> JsValue { + let mut rng = thread_rng(); + + let secret_key = SecretKey::new(&mut rng); + let one_time_private_key = PrivateKey::new(secret_key, Network::Testnet).to_string(); + + JsValue::from_str(&one_time_private_key) +} diff --git a/packages/wasm-dpp/src/identity/identity_public_key/mod.rs b/packages/wasm-dpp/src/identity/identity_public_key/mod.rs index 4f5ab91492c..92500dd1604 100644 --- a/packages/wasm-dpp/src/identity/identity_public_key/mod.rs +++ b/packages/wasm-dpp/src/identity/identity_public_key/mod.rs @@ -6,7 +6,7 @@ use wasm_bindgen::prelude::*; use crate::utils::{Inner, WithJsError}; use crate::{buffer::Buffer, utils, with_js_error}; -use dpp::identity::{IdentityPublicKey, KeyID}; +use dpp::identity::{IdentityPublicKey, KeyID, TimestampMillis}; use dpp::platform_value::BinaryData; use dpp::Convertible; @@ -67,8 +67,8 @@ impl IdentityPublicKeyWasm { } #[wasm_bindgen(js_name=getData)] - pub fn get_data(&self) -> Vec { - self.0.data.to_vec() + pub fn get_data(&self) -> Buffer { + Buffer::from_bytes_owned(self.0.data.to_vec()) } #[wasm_bindgen(js_name=setPurpose)] @@ -108,14 +108,16 @@ impl IdentityPublicKeyWasm { } #[wasm_bindgen(js_name=setDisabledAt)] - pub fn set_disabled_at(&mut self, timestamp: u32) { - // TODO: It's not gonna work, must be BigInt - self.0.set_disabled_at(timestamp as u64); + pub fn set_disabled_at(&mut self, timestamp: js_sys::Date) { + self.0 + .set_disabled_at(timestamp.get_time() as TimestampMillis); } #[wasm_bindgen(js_name=getDisabledAt)] - pub fn get_disabled_at(&self) -> Option { - self.0.disabled_at.map(|timestamp| timestamp as f64) + pub fn get_disabled_at(&self) -> Option { + self.0 + .disabled_at + .map(|timestamp| js_sys::Date::new(&JsValue::from_f64(timestamp as f64))) } #[wasm_bindgen(js_name=hash)] diff --git a/packages/wasm-dpp/src/identity/mod.rs b/packages/wasm-dpp/src/identity/mod.rs index 1230c689ebb..b45dd64db97 100644 --- a/packages/wasm-dpp/src/identity/mod.rs +++ b/packages/wasm-dpp/src/identity/mod.rs @@ -15,12 +15,13 @@ use dpp::metadata::Metadata; use dpp::{Convertible, ProtocolError}; use crate::identifier::IdentifierWrapper; -use crate::utils::{to_vec_of_serde_values, WithJsError}; +use crate::utils::{to_vec_of_serde_values, IntoWasm, WithJsError}; use crate::MetadataWasm; use crate::{utils, with_js_error}; pub use identity_public_key::*; use crate::buffer::Buffer; +use crate::errors::from_dpp_err; pub use state_transition::*; pub mod errors; @@ -50,7 +51,7 @@ impl IdentityWasm { let raw_identity: Value = serde_json::from_str(&identity_json).map_err(|e| e.to_string())?; - let identity = Identity::from_json(raw_identity).unwrap(); + let identity = Identity::from_json(raw_identity).map_err(from_dpp_err)?; Ok(IdentityWasm(identity)) } @@ -148,8 +149,13 @@ impl IdentityWasm { } #[wasm_bindgen(js_name=setMetadata)] - pub fn set_metadata(&mut self, metadata: MetadataWasm) { - self.0.set_metadata(metadata.into()); + pub fn set_metadata(&mut self, metadata: JsValue) -> Result<(), JsValue> { + if !metadata.is_falsy() { + let metadata = metadata.to_wasm::("Metadata")?; + self.0.set_metadata(metadata.to_owned().into()) + } + + Ok(()) } #[wasm_bindgen(js_name=getMetadata)] diff --git a/packages/wasm-dpp/src/identity/state_transition/identity_public_key_transitions.rs b/packages/wasm-dpp/src/identity/state_transition/identity_public_key_transitions.rs index fa5ea7d3a95..c8c3b272d95 100644 --- a/packages/wasm-dpp/src/identity/state_transition/identity_public_key_transitions.rs +++ b/packages/wasm-dpp/src/identity/state_transition/identity_public_key_transitions.rs @@ -64,8 +64,8 @@ impl IdentityPublicKeyWithWitnessWasm { } #[wasm_bindgen(js_name=getData)] - pub fn get_data(&self) -> Vec { - self.0.data.to_vec() + pub fn get_data(&self) -> Buffer { + Buffer::from_bytes_owned(self.0.data.to_vec()) } #[wasm_bindgen(js_name=setPurpose)] diff --git a/packages/wasm-dpp/src/lib.rs b/packages/wasm-dpp/src/lib.rs index 39f810a3b17..fff1a8c5885 100644 --- a/packages/wasm-dpp/src/lib.rs +++ b/packages/wasm-dpp/src/lib.rs @@ -29,5 +29,6 @@ mod bls_adapter; mod buffer; mod decode_protocol_entity; mod entropy_generator; +mod generate_temporary_ecdsa_private_key; mod lodash; mod validation; diff --git a/packages/wasm-dpp/src/metadata.rs b/packages/wasm-dpp/src/metadata.rs index e0e62ab7c56..b482473f08e 100644 --- a/packages/wasm-dpp/src/metadata.rs +++ b/packages/wasm-dpp/src/metadata.rs @@ -9,7 +9,7 @@ use dpp::util::deserializer::ProtocolVersion; use dpp::util::json_value::JsonValueExt; #[wasm_bindgen(js_name=Metadata)] -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct MetadataWasm(Metadata); impl std::convert::From for MetadataWasm { diff --git a/packages/wasm-dpp/src/state_repository.rs b/packages/wasm-dpp/src/state_repository.rs index b3854b12507..49ae586d905 100644 --- a/packages/wasm-dpp/src/state_repository.rs +++ b/packages/wasm-dpp/src/state_repository.rs @@ -54,6 +54,13 @@ extern "C" { execution_context: &JsValue, ) -> Result<(), JsValue>; + #[wasm_bindgen(catch, structural, method, js_name=updateDataContract)] + pub async fn update_data_contract( + this: &ExternalStateRepositoryLike, + data_contract: DataContractWasm, + execution_context: &JsValue, + ) -> Result<(), JsValue>; + #[wasm_bindgen(catch, structural, method, js_name=createDocument)] pub async fn create_document( this: &ExternalStateRepositoryLike, @@ -216,6 +223,15 @@ extern "C" { execution_context: &JsValue, ) -> Result<(), JsValue>; + #[wasm_bindgen(catch, structural, method, js_name=fetchSMLStore)] + pub async fn fetch_sml_store(this: &ExternalStateRepositoryLike) -> Result; + + #[wasm_bindgen(catch, structural, method, js_name=isInTheValidMasterNodesList)] + async fn is_in_the_valid_master_nodes_list( + this: &ExternalStateRepositoryLike, + id: Buffer, + ) -> Result; + #[wasm_bindgen(catch, structural, method, js_name=fetchLatestPlatformBlockHeader)] pub async fn fetch_latest_platform_block_header( this: &ExternalStateRepositoryLike, @@ -323,6 +339,17 @@ impl StateRepositoryLike for ExternalStateRepositoryLikeWrapper { .map_err(from_js_error) } + async fn update_data_contract<'a>( + &self, + data_contract: DataContract, + execution_context: Option<&'a StateTransitionExecutionContext>, + ) -> anyhow::Result<()> { + self.0 + .update_data_contract(data_contract.into(), &ctx_to_js_value(execution_context)) + .await + .map_err(from_js_error) + } + async fn fetch_documents<'a>( &self, contract_id: &Identifier, @@ -454,7 +481,7 @@ impl StateRepositoryLike for ExternalStateRepositoryLikeWrapper { .await .map_err(from_js_error)?; - if maybe_identity.is_undefined() { + if maybe_identity.is_undefined() || maybe_identity.is_null() { return Ok(None); } @@ -542,7 +569,7 @@ impl StateRepositoryLike for ExternalStateRepositoryLikeWrapper { .await .map_err(from_js_error)?; - if maybe_balance.is_undefined() { + if maybe_balance.is_undefined() || maybe_balance.is_null() { return Ok(None); } @@ -567,7 +594,7 @@ impl StateRepositoryLike for ExternalStateRepositoryLikeWrapper { .await .map_err(from_js_error)?; - if maybe_balance.is_undefined() { + if maybe_balance.is_undefined() || maybe_balance.is_null() { return Ok(None); } @@ -629,6 +656,7 @@ impl StateRepositoryLike for ExternalStateRepositoryLikeWrapper { _amount: u64, _execution_context: Option<&'a StateTransitionExecutionContext>, ) -> anyhow::Result<()> { + // TODO(wasm-dpp): !!!Missing implementation will hang js-drive and no one will have a clue what's going on todo!() } @@ -649,7 +677,7 @@ impl StateRepositoryLike for ExternalStateRepositoryLikeWrapper { .await .map_err(from_js_error)?; - if maybe_height.is_undefined() { + if maybe_height.is_undefined() || maybe_height.is_null() { return Ok(None); } @@ -730,7 +758,20 @@ impl StateRepositoryLike for ExternalStateRepositoryLikeWrapper { todo!() } + async fn is_in_the_valid_master_nodes_list(&self, id: [u8; 32]) -> anyhow::Result { + let is_valid = self + .0 + .is_in_the_valid_master_nodes_list(Buffer::from_bytes(&id)) + .await + .map_err(from_js_error)?; + + is_valid + .as_bool() + .ok_or_else(|| anyhow!("Value is not a bool")) + } + async fn fetch_latest_withdrawal_transaction_index(&self) -> anyhow::Result { + // TODO(wasm-dpp): !!!Missing implementation will hang js-drive and no one will have a clue what's going on todo!() } @@ -739,6 +780,7 @@ impl StateRepositoryLike for ExternalStateRepositoryLikeWrapper { _index: u64, _transaction_bytes: Vec, ) -> anyhow::Result<()> { + // TODO(wasm-dpp): !!!Missing implementation will hang js-drive and no one will have a clue what's going on todo!() } diff --git a/packages/wasm-dpp/src/state_transition/errors/invalid_state_transition_error.rs b/packages/wasm-dpp/src/state_transition/errors/invalid_state_transition_error.rs index 470c112a6ea..90f201e2cfb 100644 --- a/packages/wasm-dpp/src/state_transition/errors/invalid_state_transition_error.rs +++ b/packages/wasm-dpp/src/state_transition/errors/invalid_state_transition_error.rs @@ -1,7 +1,10 @@ use dpp::consensus::ConsensusError; use wasm_bindgen::{prelude::wasm_bindgen, JsValue}; -use crate::errors::consensus::consensus_error::from_consensus_error_ref; +use crate::{ + buffer::Buffer, errors::consensus::consensus_error::from_consensus_error_ref, + utils::consensus_errors_from_buffers, +}; #[wasm_bindgen(js_name = InvalidStateTransitionError)] pub struct InvalidStateTransitionErrorWasm { @@ -20,6 +23,19 @@ impl InvalidStateTransitionErrorWasm { #[wasm_bindgen(js_class = InvalidStateTransitionError)] impl InvalidStateTransitionErrorWasm { + #[wasm_bindgen(constructor)] + pub fn new_wasm( + error_buffers: Vec, + raw_state_transition: JsValue, + ) -> Result { + let consensus_errors = consensus_errors_from_buffers(error_buffers)?; + + Ok(InvalidStateTransitionErrorWasm::new( + consensus_errors, + raw_state_transition, + )) + } + #[wasm_bindgen(js_name = getErrors)] pub fn get_errors(&self) -> Vec { self.errors.iter().map(from_consensus_error_ref).collect() diff --git a/packages/wasm-dpp/src/state_transition/fee/calculate_operation_fees.rs b/packages/wasm-dpp/src/state_transition/fee/calculate_operation_fees.rs index 8a270bbede5..4e24ee92e26 100644 --- a/packages/wasm-dpp/src/state_transition/fee/calculate_operation_fees.rs +++ b/packages/wasm-dpp/src/state_transition/fee/calculate_operation_fees.rs @@ -6,12 +6,9 @@ use dpp::{ }; use wasm_bindgen::prelude::*; -use crate::{ - fee::dummy_fee_result::DummyFeesResultWasm, - utils::{Inner, IntoWasm, WithJsError}, -}; +use crate::{fee::dummy_fee_result::DummyFeesResultWasm, utils::WithJsError}; -use super::OperationWasm; +use crate::state_transition::conversion::create_operation_from_wasm_instance; #[wasm_bindgen(js_name=calculateOperationFees)] pub fn calculate_operation_fees_wasm( @@ -19,8 +16,8 @@ pub fn calculate_operation_fees_wasm( ) -> Result { let mut inner_operations: Vec = vec![]; for operation in operations.iter() { - let operation = operation.to_wasm::("Operation")?.to_owned(); - inner_operations.push(operation.into_inner()) + let operation = create_operation_from_wasm_instance(&operation)?; + inner_operations.push(operation); } Ok(calculate_operation_fees(&inner_operations) diff --git a/packages/wasm-dpp/src/state_transition/fee/calculate_state_transition_fee_from_operations.rs b/packages/wasm-dpp/src/state_transition/fee/calculate_state_transition_fee_from_operations.rs new file mode 100644 index 00000000000..7303c0fcb8d --- /dev/null +++ b/packages/wasm-dpp/src/state_transition/fee/calculate_state_transition_fee_from_operations.rs @@ -0,0 +1,29 @@ +use dpp::state_transition::fee::calculate_state_transition_fee_from_operations_factory::calculate_state_transition_fee_from_operations; +use dpp::state_transition::fee::operations::Operation; +use dpp::ProtocolError; +use wasm_bindgen::prelude::*; + +use crate::fee::fee_result::FeeResultWasm; +use crate::identifier::IdentifierWrapper; +use crate::state_transition::conversion::create_operation_from_wasm_instance; +use crate::utils::WithJsError; + +#[wasm_bindgen(js_name=calculateStateTransitionFeeFromOperations)] +pub fn calculate_state_transition_fee_from_operations_wasm( + operations: js_sys::Array, + identity_id: &IdentifierWrapper, +) -> Result { + let mut inner_operations: Vec = vec![]; + for operation in operations.iter() { + let operation = create_operation_from_wasm_instance(&operation)?; + inner_operations.push(operation); + } + + Ok(calculate_state_transition_fee_from_operations( + &inner_operations, + &(identity_id.to_owned()).into(), + ) + .map_err(ProtocolError::from) + .with_js_error()? + .into()) +} diff --git a/packages/wasm-dpp/src/state_transition/fee/mod.rs b/packages/wasm-dpp/src/state_transition/fee/mod.rs index c87ea551280..ccecd5249a0 100644 --- a/packages/wasm-dpp/src/state_transition/fee/mod.rs +++ b/packages/wasm-dpp/src/state_transition/fee/mod.rs @@ -4,6 +4,7 @@ use wasm_bindgen::prelude::*; use crate::utils::Inner; mod calculate_operation_fees; mod calculate_state_transition_fee; +mod calculate_state_transition_fee_from_operations; mod dummy_fee_result; mod fee_result; mod operations; diff --git a/packages/wasm-dpp/src/state_transition/fee/operations/pre_calculated_operation.rs b/packages/wasm-dpp/src/state_transition/fee/operations/pre_calculated_operation.rs index 640c05606e2..7d29f492a4f 100644 --- a/packages/wasm-dpp/src/state_transition/fee/operations/pre_calculated_operation.rs +++ b/packages/wasm-dpp/src/state_transition/fee/operations/pre_calculated_operation.rs @@ -1,17 +1,21 @@ use crate::{fee::dummy_fee_result::DummyFeesResultWasm, utils::Inner}; +use dpp::platform_value::Error as PlatformValueError; use dpp::{ state_transition::fee::{ operations::{OperationLike, PreCalculatedOperation}, - Refunds, + Credits, Refunds, }, ProtocolError, }; use js_sys::{Array, BigInt}; +use std::collections::HashMap; use wasm_bindgen::prelude::*; +use crate::errors::value_error::PlatformValueErrorWasm; +use crate::utils::ToSerdeJSONExt; use crate::{ fee::refunds::RefundsWasm, - utils::{try_to_u64, IntoWasm, WithJsError}, + utils::{try_to_u64, WithJsError}, }; #[wasm_bindgen(js_name = "PreCalculatedOperation")] @@ -42,12 +46,40 @@ impl PreCalculatedOperationWasm { let processing_cost = try_to_u64(processing_cost).with_js_error()?; let mut refunds = vec![]; + // TODO(wasm-dpp): any chance to make this parsing simpler? :) for refund in js_fee_refunds.iter() { - let transition: Refunds = refund - .to_wasm::("Refunds")? - .to_owned() - .into_inner(); - refunds.push(transition); + let parsed_refund = refund.with_serde_to_platform_value()?; + let identifier = parsed_refund + .get_identifier("identifier") + .map_err(PlatformValueErrorWasm::from)?; + + let mut credits_per_epoch: HashMap = HashMap::new(); + if let Some(credits_per_epoch_value) = parsed_refund + .get("creditsPerEpoch") + .map_err(PlatformValueErrorWasm::from)? + { + let credits_per_epoch_map = credits_per_epoch_value.as_map().ok_or_else(|| { + let error = + PlatformValueError::PathError("Credits per epoch is not a map".to_string()); + PlatformValueErrorWasm::from(error) + })?; + + for (epoch, credits) in credits_per_epoch_map { + let epoch = epoch.to_str().map_err(PlatformValueErrorWasm::from)?; + let credits = + credits + .as_integer::() + .ok_or(PlatformValueErrorWasm::from(PlatformValueError::PathError( + "Credits per epoch is not an integer".to_string(), + )))?; + + credits_per_epoch.insert(String::from(epoch), credits); + } + } + refunds.push(Refunds { + identifier, + credits_per_epoch, + }); } Ok(PreCalculatedOperation::new(storage_cost, processing_cost, refunds).into()) @@ -92,6 +124,50 @@ impl PreCalculatedOperationWasm { None } } + + pub fn refunds_as_objects(&self) -> Result, JsValue> { + let array_refunds = Array::new(); + if let Some(refunds) = self.0.get_refunds() { + for refund in refunds { + let refund_wasm: RefundsWasm = refund.into(); + array_refunds.push(&refund_wasm.to_object()?); + } + Ok(Some(array_refunds)) + } else { + Ok(None) + } + } + + #[wasm_bindgen(js_name = toJSON)] + pub fn to_json(&self) -> Result { + let json = js_sys::Object::new(); + + js_sys::Reflect::set( + &json, + &JsValue::from_str("type"), + &JsValue::from_str("preCalculated"), + )?; + + js_sys::Reflect::set( + &json, + &JsValue::from_str("storageCost"), + &JsValue::from(self.storage_cost()?), + )?; + + js_sys::Reflect::set( + &json, + &JsValue::from_str("processingCost"), + &JsValue::from(self.processing_cost()?), + )?; + + js_sys::Reflect::set( + &json, + &JsValue::from_str("feeRefunds"), + &JsValue::from(self.refunds_as_objects()?.unwrap_or(Array::new())), + )?; + + Ok(json.into()) + } } impl Inner for PreCalculatedOperationWasm { diff --git a/packages/wasm-dpp/src/state_transition/fee/operations/read_operation.rs b/packages/wasm-dpp/src/state_transition/fee/operations/read_operation.rs index 9d980bfbdb3..e3235f9e37b 100644 --- a/packages/wasm-dpp/src/state_transition/fee/operations/read_operation.rs +++ b/packages/wasm-dpp/src/state_transition/fee/operations/read_operation.rs @@ -67,6 +67,25 @@ impl ReadOperationWasm { None } } + + #[wasm_bindgen(js_name = toJSON)] + pub fn to_json(&self) -> Result { + let json = js_sys::Object::new(); + + js_sys::Reflect::set( + &json, + &JsValue::from_str("type"), + &JsValue::from_str("read"), + )?; + + js_sys::Reflect::set( + &json, + &JsValue::from_str("valueSize"), + &JsValue::from(self.0.value_size), + )?; + + Ok(json.into()) + } } impl Inner for ReadOperationWasm { diff --git a/packages/wasm-dpp/src/state_transition/fee/operations/signature_verification_operation.rs b/packages/wasm-dpp/src/state_transition/fee/operations/signature_verification_operation.rs index 85fbc7cd360..3b747de4a6b 100644 --- a/packages/wasm-dpp/src/state_transition/fee/operations/signature_verification_operation.rs +++ b/packages/wasm-dpp/src/state_transition/fee/operations/signature_verification_operation.rs @@ -74,6 +74,21 @@ impl SignatureVerificationOperationWasm { None } } + + #[wasm_bindgen(js_name = toJSON)] + pub fn to_json(&self) -> Result { + let json = js_sys::Object::new(); + + js_sys::Reflect::set(&json, &"type".into(), &"signatureVerification".into())?; + + js_sys::Reflect::set( + &json, + &"signatureType".into(), + &JsValue::from(self.0.signature_type as u8), + )?; + + Ok(json.into()) + } } impl Inner for SignatureVerificationOperationWasm { diff --git a/packages/wasm-dpp/src/state_transition/fee/refunds.rs b/packages/wasm-dpp/src/state_transition/fee/refunds.rs index 10cbd37b5cd..6013f526ae9 100644 --- a/packages/wasm-dpp/src/state_transition/fee/refunds.rs +++ b/packages/wasm-dpp/src/state_transition/fee/refunds.rs @@ -4,6 +4,7 @@ use dpp::state_transition::fee::Refunds; use js_sys::BigInt; use wasm_bindgen::prelude::*; +use crate::buffer::Buffer; use crate::{identifier::IdentifierWrapper, utils::Inner}; #[derive(Clone)] @@ -21,6 +22,22 @@ impl RefundsWasm { pub fn credits_per_epoch(&self) -> js_sys::Map { convert_hashmap_to_jsmap(&self.0.credits_per_epoch) } + + #[wasm_bindgen(js_name=toObject)] + pub fn to_object(&self) -> Result { + let object = js_sys::Object::new(); + + let identifier = Buffer::from_bytes(self.0.identifier.as_slice()); + + js_sys::Reflect::set(&object, &"identifier".into(), &identifier)?; + js_sys::Reflect::set( + &object, + &"creditsPerEpoch".into(), + &self.credits_per_epoch(), + )?; + + Ok(object.into()) + } } impl From for RefundsWasm { diff --git a/packages/wasm-dpp/src/state_transition/mod.rs b/packages/wasm-dpp/src/state_transition/mod.rs index 1dc022b9d63..c85f84b4408 100644 --- a/packages/wasm-dpp/src/state_transition/mod.rs +++ b/packages/wasm-dpp/src/state_transition/mod.rs @@ -73,6 +73,11 @@ impl StateTransitionExecutionContextWasm { self.0.disable_dry_run(); } + #[wasm_bindgen(js_name=isDryRun)] + pub fn is_dry_run(&self) -> bool { + self.0.is_dry_run() + } + #[wasm_bindgen(js_name=addOperation)] pub fn add_operation(&self, operation: JsValue) -> Result<(), JsValue> { let operation = create_operation_from_wasm_instance(&operation)?; @@ -96,6 +101,11 @@ impl StateTransitionExecutionContextWasm { }) .collect() } + + #[wasm_bindgen(js_name=clearDryOperations)] + pub fn clear_dry_run_operations(&self) { + self.0.clear_dry_run_operations(); + } } impl Inner for StateTransitionExecutionContextWasm { diff --git a/packages/wasm-dpp/src/state_transition/state_transition_facade.rs b/packages/wasm-dpp/src/state_transition/state_transition_facade.rs index 85eb8bce8b6..9e0b2e398d5 100644 --- a/packages/wasm-dpp/src/state_transition/state_transition_facade.rs +++ b/packages/wasm-dpp/src/state_transition/state_transition_facade.rs @@ -1,4 +1,5 @@ use crate::bls_adapter::BlsAdapter; +use std::convert::TryInto; use crate::state_repository::{ExternalStateRepositoryLike, ExternalStateRepositoryLikeWrapper}; use crate::state_transition_factory::StateTransitionFactoryWasm; @@ -7,12 +8,17 @@ use crate::validation::ValidationResultWasm; use crate::with_js_error; use dpp::state_transition::state_transition_execution_context::StateTransitionExecutionContext; use dpp::state_transition::{ - StateTransitionConvert, StateTransitionFacade, StateTransitionLike, ValidateOptions, + StateTransitionConvert, StateTransitionFacade, StateTransitionLike, StateTransitionType, + ValidateOptions, }; use dpp::version::ProtocolVersionValidator; use serde::Deserialize; use crate::errors::protocol_error::from_protocol_error; +use crate::errors::value_error::PlatformValueErrorWasm; +use dpp::data_contract::state_transition::data_contract_update_transition::DataContractUpdateTransition; +use dpp::document::DocumentsBatchTransition; +use dpp::ProtocolError; use std::sync::Arc; use wasm_bindgen::prelude::*; use wasm_bindgen::JsValue; @@ -56,7 +62,21 @@ impl StateTransitionFacadeWasm { Default::default() }; - let raw_state_transition = raw_state_transition.with_serde_to_platform_value()?; + let mut raw_state_transition = raw_state_transition.with_serde_to_platform_value()?; + let state_transition_type: StateTransitionType = raw_state_transition + .get_integer::("type") + .map_err(|e| PlatformValueErrorWasm::from(e))? + .try_into() + .map_err(|_| JsValue::from_str("Invalid state transition type"))?; + + // TODO(wasm-dpp): clean values of other transitions as well? + match state_transition_type { + StateTransitionType::DataContractUpdate => { + DataContractUpdateTransition::clean_value(&mut raw_state_transition) + .map_err(|e| PlatformValueErrorWasm::from(e))?; + } + _ => {} + } let result = self .0 diff --git a/packages/wasm-dpp/src/utils.rs b/packages/wasm-dpp/src/utils.rs index 4a7b90061af..aee52dcb73a 100644 --- a/packages/wasm-dpp/src/utils.rs +++ b/packages/wasm-dpp/src/utils.rs @@ -3,17 +3,21 @@ use std::convert::TryInto; use anyhow::{anyhow, bail}; use dpp::{ + consensus::ConsensusError, dashcore::{anyhow, anyhow::Context}, ProtocolError, }; use dpp::platform_value::Value; -use js_sys::Function; +use js_sys::{Function, Uint8Array}; use serde::de::DeserializeOwned; use serde_json::Value as JsonValue; use wasm_bindgen::{convert::RefFromWasmAbi, prelude::*}; -use crate::errors::{from_dpp_err, RustConversionError}; +use crate::{ + buffer::Buffer, + errors::{from_dpp_err, RustConversionError}, +}; pub trait ToSerdeJSONExt { fn with_serde_to_json_value(&self) -> Result; @@ -280,3 +284,20 @@ pub(crate) trait Inner { fn inner(&self) -> &Self::InnerItem; fn inner_mut(&mut self) -> &mut Self::InnerItem; } + +pub(crate) fn consensus_errors_from_buffers( + errors: Vec, +) -> Result, JsValue> { + errors + .iter() + .map(|error_buffer| { + Uint8Array::new_with_byte_offset_and_length( + &error_buffer.buffer(), + error_buffer.byte_offset(), + error_buffer.length(), + ) + .to_vec() + }) + .map(|error_bytes| ConsensusError::deserialize(&error_bytes.to_vec()).with_js_error()) + .collect::, JsValue>>() +} diff --git a/packages/wasm-dpp/src/validation/validation_result.rs b/packages/wasm-dpp/src/validation/validation_result.rs index cedfeb9cd29..7c12a66ced5 100644 --- a/packages/wasm-dpp/src/validation/validation_result.rs +++ b/packages/wasm-dpp/src/validation/validation_result.rs @@ -1,6 +1,10 @@ -use crate::errors::consensus::consensus_error::from_consensus_error_ref; +use crate::{ + buffer::Buffer, + errors::consensus::consensus_error::from_consensus_error_ref, + utils::{consensus_errors_from_buffers, WithJsError}, +}; use dpp::{consensus::ConsensusError, validation::ValidationResult}; -use js_sys::JsString; +use js_sys::{JsString, Uint8Array}; use wasm_bindgen::prelude::*; #[wasm_bindgen(js_name=ValidationResult)] @@ -18,6 +22,17 @@ where #[wasm_bindgen(js_class=ValidationResult)] impl ValidationResultWasm { + #[wasm_bindgen(constructor)] + pub fn new(errors_option: Option>) -> Result { + if let Some(errors) = errors_option { + let consensus_errors: Vec = consensus_errors_from_buffers(errors)?; + + return Ok(Self(ValidationResult::new_with_errors(consensus_errors))); + } + + Ok(Self(ValidationResult::new_with_errors(vec![]))) + } + /// This is just a test method - doesn't need to be in the resulted binding. Please /// remove before shipping #[wasm_bindgen(js_name=errorsText)] @@ -48,6 +63,22 @@ impl ValidationResultWasm { JsValue::undefined() } } + + #[wasm_bindgen(js_name = addError)] + pub fn add_error_wasm(&mut self, error_buffer: Buffer) -> Result { + let error_bytes: Vec = Uint8Array::new_with_byte_offset_and_length( + &error_buffer.buffer(), + error_buffer.byte_offset(), + error_buffer.length(), + ) + .to_vec(); + + let consensus_error = ConsensusError::deserialize(&error_bytes).with_js_error()?; + + self.0.add_error(consensus_error); + + Ok(JsValue::undefined()) + } } impl ValidationResultWasm { diff --git a/packages/wasm-dpp/test/integration/dataContract/DataContractFacade.spec.js b/packages/wasm-dpp/test/integration/dataContract/DataContractFacade.spec.js index 8124b8c688f..e10b0524666 100644 --- a/packages/wasm-dpp/test/integration/dataContract/DataContractFacade.spec.js +++ b/packages/wasm-dpp/test/integration/dataContract/DataContractFacade.spec.js @@ -1,11 +1,13 @@ const getDataContractJSFixture = require('@dashevo/dpp/lib/test/fixtures/getDataContractFixture'); const crypto = require('crypto'); const getBlsAdapterMock = require('../../../lib/test/mocks/getBlsAdapterMock'); +const createStateRepositoryMock = require('../../../lib/test/mocks/createStateRepositoryMock'); +const getPrivateAndPublicKey = require('../../../lib/test/fixtures/getPrivateAndPublicKeyForSigningFixture'); const { default: loadWasmDpp } = require('../../..'); let { DashPlatformProtocol, DataContract, ValidationResult, DataContractValidator, - DataContractFactory, DataContractCreateTransition, + DataContractFactory, DataContractCreateTransition, DataContractUpdateTransition, } = require('../../..'); describe('DataContractFacade', () => { @@ -15,18 +17,21 @@ describe('DataContractFacade', () => { let blsAdapter; let rawDataContract; let dataContractWasm; + let stateTransitionMock; before(async () => { ({ DashPlatformProtocol, DataContract, ValidationResult, DataContractValidator, DataContractFactory, DataContractCreateTransition, + DataContractUpdateTransition, } = await loadWasmDpp()); }); - beforeEach(async () => { + beforeEach(async function beforeEach() { blsAdapter = await getBlsAdapterMock(); + stateTransitionMock = createStateRepositoryMock(this.sinonSandbox); dpp = new DashPlatformProtocol( - blsAdapter, {}, { generate: () => crypto.randomBytes(32) }, 1, + blsAdapter, stateTransitionMock, { generate: () => crypto.randomBytes(32) }, 1, ); dataContractJs = await getDataContractJSFixture(); @@ -92,6 +97,38 @@ describe('DataContractFacade', () => { }); }); + describe('createDataContractUpdateTransition', () => { + it('should create DataContractUpdateTransition from buffer', async () => { + const dataContractBuffer = Buffer.from('01a56324696458205a3c9565f215156cfb330ef3a4a4400a1dad7415f4f1480e072d3419bb29c12c6724736368656d61783468747470733a2f2f736368656d612e646173682e6f72672f6470702d302d342d302f6d6574612f646174612d636f6e7472616374676f776e657249645820d5199a5b19334554d5dd483af53877251584ab9a66ca777bd1b2e8d2ec4808346776657273696f6e0169646f63756d656e7473a36c6e696365446f63756d656e74a46474797065666f626a656374687265717569726564816a246372656174656441746a70726f70657274696573a1646e616d65a1647479706566737472696e67746164646974696f6e616c50726f70657274696573f46e7769746842797465417272617973a56474797065666f626a65637467696e646963657381a2646e616d6566696e646578316a70726f7065727469657381a16e6279746541727261794669656c6463617363687265717569726564816e6279746541727261794669656c646a70726f70657274696573a26e6279746541727261794669656c64a36474797065656172726179686d61784974656d731069627974654172726179f56f6964656e7469666965724669656c64a56474797065656172726179686d61784974656d731820686d696e4974656d73182069627974654172726179f570636f6e74656e744d656469615479706578216170706c69636174696f6e2f782e646173682e6470702e6964656e746966696572746164646974696f6e616c50726f70657274696573f46f696e6465786564446f63756d656e74a56474797065666f626a65637467696e646963657386a3646e616d6566696e646578316a70726f7065727469657382a168246f776e6572496463617363a16966697273744e616d656361736366756e69717565f5a3646e616d6566696e646578326a70726f7065727469657382a168246f776e6572496463617363a1686c6173744e616d656361736366756e69717565f5a2646e616d6566696e646578336a70726f7065727469657381a1686c6173744e616d6563617363a2646e616d6566696e646578346a70726f7065727469657382a16a2463726561746564417463617363a16a2475706461746564417463617363a2646e616d6566696e646578356a70726f7065727469657381a16a2475706461746564417463617363a2646e616d6566696e646578366a70726f7065727469657381a16a2463726561746564417463617363687265717569726564846966697273744e616d656a246372656174656441746a24757064617465644174686c6173744e616d656a70726f70657274696573a2686c6173744e616d65a2647479706566737472696e67696d61784c656e677468183f6966697273744e616d65a2647479706566737472696e67696d61784c656e677468183f746164646974696f6e616c50726f70657274696573f4', 'hex'); + + const dataContract = await dpp.dataContract.createFromBuffer(dataContractBuffer); + + const updatedDataContract = await dpp.dataContract.createFromObject( + dataContract.toObject(), + ); + + updatedDataContract.incrementVersion(); + + const dataContractUpdateTransition = dpp.dataContract + .createDataContractUpdateTransition(updatedDataContract); + + const { identityPublicKey, privateKey } = await getPrivateAndPublicKey(); + + dataContractUpdateTransition.sign( + identityPublicKey, + privateKey, + await getBlsAdapterMock(), + ); + + const buf = dataContractUpdateTransition.toBuffer(); + stateTransitionMock.fetchDataContract.resolves(dataContract); + + const st = await dpp.stateTransition.createFromBuffer(buf); + + expect(st).to.be.an.instanceOf(DataContractUpdateTransition); + }); + }); + describe('validate', () => { it('should validate DataContract', async () => { const result = await dpp.dataContract.validate(rawDataContract); diff --git a/packages/wasm-dpp/test/integration/dataContract/validation/validateDataContractFactory.spec.js b/packages/wasm-dpp/test/integration/dataContract/validation/validateDataContractFactory.spec.js index c4848023c71..d318e7f8c51 100644 --- a/packages/wasm-dpp/test/integration/dataContract/validation/validateDataContractFactory.spec.js +++ b/packages/wasm-dpp/test/integration/dataContract/validation/validateDataContractFactory.spec.js @@ -1074,7 +1074,7 @@ describe('validateDataContractFactory', () => { properties: { something: { type: 'string', - format: 'url', + format: 'uri', }, }, additionalProperties: false, @@ -1098,7 +1098,7 @@ describe('validateDataContractFactory', () => { properties: { something: { type: 'string', - format: 'url', + format: 'uri', maxLength: 60000, }, }, diff --git a/packages/wasm-dpp/test/integration/identity/stateTransition/IdentityUpdateTransition/validation/state/validateIdentityUpdateTransitionStateFactory.spec.js b/packages/wasm-dpp/test/integration/identity/stateTransition/IdentityUpdateTransition/validation/state/validateIdentityUpdateTransitionStateFactory.spec.js index c763c5841b7..a620b50b5c6 100644 --- a/packages/wasm-dpp/test/integration/identity/stateTransition/IdentityUpdateTransition/validation/state/validateIdentityUpdateTransitionStateFactory.spec.js +++ b/packages/wasm-dpp/test/integration/identity/stateTransition/IdentityUpdateTransition/validation/state/validateIdentityUpdateTransitionStateFactory.spec.js @@ -112,7 +112,7 @@ describe('validateIdentityUpdateTransitionStateFactory', () => { it('should return IdentityPublicKeyIsDisabledError if disabling public key is already disabled', async () => { const keys = identity.getPublicKeys(); - keys[0].setDisabledAt(new Date().getTime()); + keys[0].setDisabledAt(new Date()); identity.setPublicKeys(keys); stateTransition.setPublicKeyIdsToDisable([0]); diff --git a/packages/wasm-dpp/test/integration/util/generateTemporaryEcdsaPrivateKey.spec.js b/packages/wasm-dpp/test/integration/util/generateTemporaryEcdsaPrivateKey.spec.js new file mode 100644 index 00000000000..ca4bb7182af --- /dev/null +++ b/packages/wasm-dpp/test/integration/util/generateTemporaryEcdsaPrivateKey.spec.js @@ -0,0 +1,17 @@ +const { PrivateKey } = require('@dashevo/dashcore-lib'); +const { default: loadWasmDpp } = require('../../..'); + +let { generateTemporaryEcdsaPrivateKey } = require('../../..'); + +describe('generateTemporaryEcdsaPrivateKey', () => { + beforeEach(async () => { + ({ generateTemporaryEcdsaPrivateKey } = await loadWasmDpp()); + }); + + it('should generate a valid private key', () => { + const keyBase64 = generateTemporaryEcdsaPrivateKey(); + + // eslint-disable-next-line + const _key = new PrivateKey(keyBase64); + }); +}); diff --git a/packages/wasm-dpp/test/unit/dataContract/DataContract.spec.js b/packages/wasm-dpp/test/unit/dataContract/DataContract.spec.js index 5d8072feb55..8197e3be90f 100644 --- a/packages/wasm-dpp/test/unit/dataContract/DataContract.spec.js +++ b/packages/wasm-dpp/test/unit/dataContract/DataContract.spec.js @@ -189,6 +189,7 @@ describe('DataContract', () => { expect(anotherDocuments).to.have.property(anotherType); expect(anotherDocuments[anotherType]).to.deep.equal(anotherDefinition); + expect(dataContract.isDocumentDefined(anotherType)).to.be.true(); }); }); diff --git a/packages/wasm-dpp/test/unit/dataContract/stateTransition/DataContractUpdateTransition/applyDataContractUpdateTransitionFactory.spec.js b/packages/wasm-dpp/test/unit/dataContract/stateTransition/DataContractUpdateTransition/applyDataContractUpdateTransitionFactory.spec.js index 82a0a1b8020..b3f60695336 100644 --- a/packages/wasm-dpp/test/unit/dataContract/stateTransition/DataContractUpdateTransition/applyDataContractUpdateTransitionFactory.spec.js +++ b/packages/wasm-dpp/test/unit/dataContract/stateTransition/DataContractUpdateTransition/applyDataContractUpdateTransitionFactory.spec.js @@ -34,7 +34,7 @@ describe('applyDataContractUpdateTransitionFactory', () => { stateTransition.setExecutionContext(executionContext); const stateRepositoryLike = { - storeDataContract: async () => { + updateDataContract: async () => { dataContractStored = true; }, }; diff --git a/packages/wasm-dpp/test/unit/document/Document.spec.js b/packages/wasm-dpp/test/unit/document/Document.spec.js index c366066d243..a728c43eef0 100644 --- a/packages/wasm-dpp/test/unit/document/Document.spec.js +++ b/packages/wasm-dpp/test/unit/document/Document.spec.js @@ -277,7 +277,7 @@ describe('Document', () => { document = new ExtendedDocument(rawDocument, dataContract); - expect(document.getCreatedAt()).to.equal(rawDocument.$createdAt); + expect(document.getCreatedAt().getTime()).to.equal(rawDocument.$createdAt); }); it('should create Document with $updatedAt and data if present', async () => { @@ -298,7 +298,7 @@ describe('Document', () => { document = new ExtendedDocument(rawDocument, dataContract); - expect(document.getUpdatedAt()).to.equal(rawDocument.$updatedAt); + expect(document.getUpdatedAt().getTime()).to.equal(rawDocument.$updatedAt); }); }); @@ -461,41 +461,41 @@ describe('Document', () => { describe('#setCreatedAt', () => { it('should set $createdAt', () => { - const time = new Date().getTime(); + const time = new Date(); document.setCreatedAt(time); - expect(document.getCreatedAt()).to.equal(time); + expect(document.getCreatedAt()).to.deep.equal(time); }); }); describe('#getCreatedAt', () => { it('should return $createdAt', () => { - const time = new Date().getTime(); + const time = new Date(); document.setCreatedAt(time); - expect(document.getCreatedAt()).to.equal(time); + expect(document.getCreatedAt()).to.deep.equal(time); }); }); describe('#setUpdatedAt', () => { it('should set $updatedAt', () => { - const time = new Date().getTime(); + const time = new Date(); document.setUpdatedAt(time); - expect(document.getUpdatedAt()).to.equal(time); + expect(document.getUpdatedAt()).to.deep.equal(time); }); }); describe('#getUpdatedAt', () => { it('should return $updatedAt', () => { - const time = new Date().getTime(); + const time = new Date(); document.setUpdatedAt(time); - expect(document.getUpdatedAt()).to.equal(time); + expect(document.getUpdatedAt()).to.deep.equal(time); }); }); }); diff --git a/packages/wasm-dpp/test/unit/document/DocumentFactory.spec.js b/packages/wasm-dpp/test/unit/document/DocumentFactory.spec.js index 22177e253b0..b8102c8dc8e 100644 --- a/packages/wasm-dpp/test/unit/document/DocumentFactory.spec.js +++ b/packages/wasm-dpp/test/unit/document/DocumentFactory.spec.js @@ -154,7 +154,7 @@ describe('DocumentFactory', () => { // in a true unit test. Not here. expect(newDocument.getEntropy()).not.to.deep.be.equal(Buffer.alloc(32)); - expect(newDocument.getCreatedAt()).to.be.an('number'); + expect(newDocument.getCreatedAt()).to.be.an.instanceOf(Date); }); it('should throw an error if type is not defined', () => { diff --git a/packages/wasm-dpp/test/unit/document/stateTransition/DocumetsBatchTransition/applyDocumentsBatchTransitionFactory.spec.js b/packages/wasm-dpp/test/unit/document/stateTransition/DocumetsBatchTransition/applyDocumentsBatchTransitionFactory.spec.js index 58f6b9d0c27..ff0eb0f436e 100644 --- a/packages/wasm-dpp/test/unit/document/stateTransition/DocumetsBatchTransition/applyDocumentsBatchTransitionFactory.spec.js +++ b/packages/wasm-dpp/test/unit/document/stateTransition/DocumetsBatchTransition/applyDocumentsBatchTransitionFactory.spec.js @@ -242,7 +242,7 @@ describe('applyDocumentsBatchTransitionFactory', () => { $type: documentTransition.getType(), $dataContractId: documentTransition.getDataContractId(), $ownerId: ownerId, - $createdAt: documentTransition.getUpdatedAt(), + $createdAt: documentTransition.getUpdatedAt().getTime(), ...documentTransition.getData(), }, documentTransition.getDataContract()); diff --git a/packages/wasm-dpp/test/unit/document/stateTransition/DocumetsBatchTransition/validation/state/validateDocumentsBatchTransitionStateFactory.spec.js b/packages/wasm-dpp/test/unit/document/stateTransition/DocumetsBatchTransition/validation/state/validateDocumentsBatchTransitionStateFactory.spec.js index 7f1182c6da0..70454eb0c09 100644 --- a/packages/wasm-dpp/test/unit/document/stateTransition/DocumetsBatchTransition/validation/state/validateDocumentsBatchTransitionStateFactory.spec.js +++ b/packages/wasm-dpp/test/unit/document/stateTransition/DocumetsBatchTransition/validation/state/validateDocumentsBatchTransitionStateFactory.spec.js @@ -233,7 +233,7 @@ describe('validateDocumentsBatchTransitionStateFactory', () => { transitions: documentTransitionsJs.map((t) => t.toObject()), }, [dataContract]); - documents[0].setCreatedAt(replaceDocument.getCreatedAt().getMilliseconds()); + documents[0].setCreatedAt(replaceDocument.getCreatedAt()); stateRepositoryMock.fetchDocuments.resolves([documents[0].getDocument()]); const result = await validateDocumentsBatchTransitionState( @@ -352,7 +352,7 @@ describe('validateDocumentsBatchTransitionStateFactory', () => { const transitions = stateTransition.getTransitions(); transitions.forEach((t) => { // eslint-disable-next-line no-param-reassign - t.setUpdatedAt(new Date().getMilliseconds()); + t.setUpdatedAt(new Date()); }); stateTransition.setTransitions(transitions); @@ -380,8 +380,8 @@ describe('validateDocumentsBatchTransitionStateFactory', () => { const transitions = stateTransition.getTransitions(); transitions.forEach((t) => { - const createdAtMinus6Mins = t.getCreatedAt() - (6 * 60 * 1000); - t.setCreatedAt(createdAtMinus6Mins); + const createdAtMinus6Mins = t.getCreatedAt().getTime() - (6 * 60 * 1000); + t.setCreatedAt(new Date(createdAtMinus6Mins)); t.setUpdatedAt(undefined); }); stateTransition.setTransitions(transitions); @@ -418,8 +418,8 @@ describe('validateDocumentsBatchTransitionStateFactory', () => { const transitions = stateTransition.getTransitions(); transitions.forEach((t) => { - const createdAtMinus6Mins = t.getUpdatedAt() - (6 * 60 * 1000); - t.setUpdatedAt(createdAtMinus6Mins); + const createdAtMinus6Mins = t.getUpdatedAt().getTime() - (6 * 60 * 1000); + t.setUpdatedAt(new Date(createdAtMinus6Mins)); t.setCreatedAt(undefined); }); stateTransition.setTransitions(transitions); @@ -466,8 +466,8 @@ describe('validateDocumentsBatchTransitionStateFactory', () => { const transitions = stateTransition.getTransitions(); transitions.forEach((t) => { - const createdAtMinus6Mins = t.getUpdatedAt() - (6 * 60 * 1000); - t.setUpdatedAt(createdAtMinus6Mins); + const createdAtMinus6Mins = t.getUpdatedAt().getTime() - (6 * 60 * 1000); + t.setUpdatedAt(new Date(createdAtMinus6Mins)); t.setCreatedAt(undefined); }); stateTransition.setTransitions(transitions); @@ -499,7 +499,7 @@ describe('validateDocumentsBatchTransitionStateFactory', () => { const transitions = stateTransition.getTransitions(); transitions.forEach((t) => { // eslint-disable-next-line no-param-reassign - t.setUpdatedAt(new Date().getMilliseconds()); + t.setUpdatedAt(new Date()); }); stateTransition.getExecutionContext().enableDryRun(); @@ -534,8 +534,8 @@ describe('validateDocumentsBatchTransitionStateFactory', () => { const transitions = stateTransition.getTransitions(); transitions.forEach((t) => { - const createdAtMinus6Mins = t.getUpdatedAt() - (6 * 60 * 1000); - t.setUpdatedAt(createdAtMinus6Mins); + const createdAtMinus6Mins = t.getUpdatedAt().getTime() - (6 * 60 * 1000); + t.setUpdatedAt(new Date(createdAtMinus6Mins)); }); stateTransition.setTransitions(transitions); @@ -581,8 +581,8 @@ describe('validateDocumentsBatchTransitionStateFactory', () => { stateRepositoryMock.fetchExtendedDocuments.resolves([documentToReturn]); const transitions = stateTransition.getTransitions(); transitions.forEach((t) => { - const createdAtMinus6Mins = t.getUpdatedAt() - (6 * 60 * 1000); - t.setUpdatedAt(createdAtMinus6Mins); + const createdAtMinus6Mins = t.getUpdatedAt().getTime() - (6 * 60 * 1000); + t.setUpdatedAt(new Date(createdAtMinus6Mins)); }); stateTransition.setTransitions(transitions); stateTransition.getExecutionContext().enableDryRun(); diff --git a/packages/wasm-dpp/test/unit/identity/IdentityPublicKey.spec.js b/packages/wasm-dpp/test/unit/identity/IdentityPublicKey.spec.js index 5652950a6ef..ff56b095a39 100644 --- a/packages/wasm-dpp/test/unit/identity/IdentityPublicKey.spec.js +++ b/packages/wasm-dpp/test/unit/identity/IdentityPublicKey.spec.js @@ -119,17 +119,19 @@ describe('IdentityPublicKey', () => { describe('#setDisabledAt', () => { it('should set disabledAt', () => { - publicKey.setDisabledAt(123); + const now = new Date(); + publicKey.setDisabledAt(now); - expect(publicKey.getDisabledAt()).to.equal(123); + expect(publicKey.getDisabledAt()).to.deep.equal(now); }); }); describe('#getDisabledAt', () => { it('should return disabledAt', () => { - publicKey.setDisabledAt(42); + const now = new Date(); + publicKey.setDisabledAt(now); - expect(publicKey.getDisabledAt()).to.equal(42); + expect(publicKey.getDisabledAt()).to.deep.equal(now); }); }); @@ -218,7 +220,8 @@ describe('IdentityPublicKey', () => { }); it('should return JSON representation with optional properties', () => { - publicKey.setDisabledAt(42); + const now = new Date(); + publicKey.setDisabledAt(now); const jsonPublicKey = publicKey.toJSON(); @@ -229,7 +232,7 @@ describe('IdentityPublicKey', () => { purpose: IdentityPublicKey.PURPOSES.AUTHENTICATION, securityLevel: IdentityPublicKey.SECURITY_LEVELS.MASTER, readOnly: false, - disabledAt: 42, + disabledAt: now.getTime(), }); }); }); diff --git a/packages/wasm-dpp/test/unit/stateTransition/StateTransitionExecutionContext.spec.js b/packages/wasm-dpp/test/unit/stateTransition/StateTransitionExecutionContext.spec.js index 7975bd4690c..1c93b9f9e07 100644 --- a/packages/wasm-dpp/test/unit/stateTransition/StateTransitionExecutionContext.spec.js +++ b/packages/wasm-dpp/test/unit/stateTransition/StateTransitionExecutionContext.spec.js @@ -36,7 +36,10 @@ describe('StateTransitionExecutionContext', () => { }); it('should add PreCalculatedOperation', () => { - executionContext.addOperation(new PreCalculatedOperation(1, 1, [])); + executionContext.addOperation(new PreCalculatedOperation(1, 1, [{ + identifier: Buffer.alloc(32).fill(32), + creditsPerEpoch: { 0: 9991498 }, + }])); const operations = executionContext.getOperations(); expect(operations[0]).to.be.instanceOf(PreCalculatedOperation); }); diff --git a/packages/wasm-dpp/test/unit/stateTransition/StateTransitionFactory.spec.js b/packages/wasm-dpp/test/unit/stateTransition/StateTransitionFactory.spec.js index b12036924b0..6cc06da0d66 100644 --- a/packages/wasm-dpp/test/unit/stateTransition/StateTransitionFactory.spec.js +++ b/packages/wasm-dpp/test/unit/stateTransition/StateTransitionFactory.spec.js @@ -88,8 +88,9 @@ describe('StateTransitionFactory', function main() { expect(result.toObject()).to.deep.equal(stateTransition.toObject()); }); - it('should throw InvalidStateTransition error in case validation failed', async () => { + it.skip('should throw InvalidStateTransition error in case validation failed', async () => { // CBOR that have invalid "type" property + // TODO: make it an actually missing field isntead of an invalid value const stateTransitionHex = '01a56c64617461436f6e7472616374a66f70726f746f636f6c56657273696f6e0163246964982018a318b611186f184718781848187d186318441830182c185518fe18e318ff188b18eb185918490218ac1831187b1873184a182c18d9189b1886182418bf6724736368656d61783468747470733a2f2f736368656d612e646173682e6f72672f6470702d302d342d302f6d6574612f646174612d636f6e74726163746776657273696f6e01676f776e657249649820187618a6185c189e18651833183d18aa02189e0d18a61869182818c107183e188908184f183818d018220418c01839161860187418ae18dd189969646f63756d656e7473a76f696e6465786564446f63756d656e74a56474797065666f626a65637467696e646963657386a3646e616d6566696e646578316a70726f7065727469657382a168246f776e6572496463617363a16966697273744e616d656361736366756e69717565f5a3646e616d6566696e646578326a70726f7065727469657382a168246f776e6572496463617363a1686c6173744e616d656361736366756e69717565f5a3646e616d6566696e646578336a70726f7065727469657381a1686c6173744e616d656361736366756e69717565f4a2646e616d6566696e646578346a70726f7065727469657382a16a2463726561746564417463617363a16a2475706461746564417463617363a2646e616d6566696e646578356a70726f7065727469657381a16a2475706461746564417463617363a2646e616d6566696e646578366a70726f7065727469657381a16a24637265617465644174636173636a70726f70657274696573a36966697273744e616d65a2647479706566737472696e67696d61784c656e677468183f686c6173744e616d65a2647479706566737472696e67696d61784c656e677468183f6d6f7468657250726f7065727479a2647479706566737472696e67696d61784c656e677468182a687265717569726564846966697273744e616d656a246372656174656441746a24757064617465644174686c6173744e616d65746164646974696f6e616c50726f70657274696573f46c6e696365446f63756d656e74a46474797065666f626a6563746a70726f70657274696573a1646e616d65a1647479706566737472696e67687265717569726564816a24637265617465644174746164646974696f6e616c50726f70657274696573f46e6e6f54696d65446f63756d656e74a36474797065666f626a6563746a70726f70657274696573a1646e616d65a1647479706566737472696e67746164646974696f6e616c50726f70657274696573f4781d6f7074696f6e616c556e69717565496e6465786564446f63756d656e74a56474797065666f626a6563746a70726f70657274696573a46966697273744e616d65a2647479706566737472696e67696d61784c656e677468183f686c6173744e616d65a2647479706566737472696e67696d61784c656e677468183f67636f756e747279a2647479706566737472696e67696d61784c656e677468183f6463697479a2647479706566737472696e67696d61784c656e677468183f67696e646963657383a3646e616d6566696e646578316a70726f7065727469657381a16966697273744e616d656361736366756e69717565f5a3646e616d6566696e646578326a70726f7065727469657383a168246f776e6572496463617363a16966697273744e616d6563617363a1686c6173744e616d656361736366756e69717565f5a3646e616d6566696e646578336a70726f7065727469657382a167636f756e74727963617363a164636974796361736366756e69717565f5687265717569726564826966697273744e616d65686c6173744e616d65746164646974696f6e616c50726f70657274696573f46e707265747479446f63756d656e74a46474797065666f626a6563746a70726f70657274696573a1686c6173744e616d65a1647479706566737472696e6768726571756972656482686c6173744e616d656a24757064617465644174746164646974696f6e616c50726f70657274696573f46b756e697175654461746573a56474797065666f626a65637467696e646963657382a3646e616d6566696e646578316a70726f7065727469657382a16a2463726561746564417463617363a16a247570646174656441746361736366756e69717565f5a2646e616d6566696e646578326a70726f7065727469657381a16a24757064617465644174636173636a70726f70657274696573a26966697273744e616d65a1647479706566737472696e67686c6173744e616d65a1647479706566737472696e67687265717569726564836966697273744e616d656a246372656174656441746a24757064617465644174746164646974696f6e616c50726f70657274696573f46e7769746842797465417272617973a56474797065666f626a65637467696e646963657381a2646e616d6566696e646578316a70726f7065727469657381a16e6279746541727261794669656c64636173636a70726f70657274696573a26e6279746541727261794669656c64a3647479706565617272617969627974654172726179f5686d61784974656d73106f6964656e7469666965724669656c64a5647479706565617272617969627974654172726179f570636f6e74656e744d656469615479706578216170706c69636174696f6e2f782e646173682e6470702e6964656e746966696572686d696e4974656d731820686d61784974656d731820687265717569726564816e6279746541727261794669656c64746164646974696f6e616c50726f70657274696573f464747970652267656e74726f70799820189618d10418b2071882188e188818fc18b7189818dd185c18811881189b1867187912183d184d187118ff1866181d185f1839188718ea1824185113747369676e61747572655075626c69634b6579496400697369676e617475726598410000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000'; const stateTransitionBuffer = Buffer.from(stateTransitionHex, 'hex'); diff --git a/packages/wasm-dpp/test/unit/stateTransition/validation/validateStateTransitionIdentitySignatureFactory.spec.js b/packages/wasm-dpp/test/unit/stateTransition/validation/validateStateTransitionIdentitySignatureFactory.spec.js index 6ea8d48c3ea..9200f17f087 100644 --- a/packages/wasm-dpp/test/unit/stateTransition/validation/validateStateTransitionIdentitySignatureFactory.spec.js +++ b/packages/wasm-dpp/test/unit/stateTransition/validation/validateStateTransitionIdentitySignatureFactory.spec.js @@ -275,7 +275,7 @@ describe('validateStateTransitionIdentitySignatureFactory', () => { it('should return PublicKeyIsDisabledConsensusError if PublicKeyIsDisabledError was thrown', async () => { const publicKeys = identity.getPublicKeys(); - publicKeys[2].setDisabledAt(Date.now()); + publicKeys[2].setDisabledAt(new Date()); identity.setPublicKeys(publicKeys); const result = await validateStateTransitionIdentitySignature( @@ -315,7 +315,7 @@ describe('validateStateTransitionIdentitySignatureFactory', () => { it('should not verify signature on dry run', async () => { // This will produce an error during signature validation const publicKeys = identity.getPublicKeys(); - publicKeys[2].setDisabledAt(Date.now()); + publicKeys[2].setDisabledAt(new Date()); identity.setPublicKeys(publicKeys); executionContext.enableDryRun(); From 0dfcd83b62cbaa92ea8d14a5b91bd61fb834146f Mon Sep 17 00:00:00 2001 From: Anton Suprunchuk Date: Tue, 11 Apr 2023 18:40:28 +0700 Subject: [PATCH 2/6] run format --- packages/rs-drive-verify-c-binding/build.rs | 2 -- packages/rs-drive-verify-c-binding/src/lib.rs | 4 ++-- packages/rs-drive-verify-c-binding/src/util.rs | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/packages/rs-drive-verify-c-binding/build.rs b/packages/rs-drive-verify-c-binding/build.rs index 9369ce57341..1d94716d7fc 100644 --- a/packages/rs-drive-verify-c-binding/build.rs +++ b/packages/rs-drive-verify-c-binding/build.rs @@ -1,5 +1,3 @@ - - use std::env; fn main() { diff --git a/packages/rs-drive-verify-c-binding/src/lib.rs b/packages/rs-drive-verify-c-binding/src/lib.rs index ebf54d86c68..af767acdb12 100644 --- a/packages/rs-drive-verify-c-binding/src/lib.rs +++ b/packages/rs-drive-verify-c-binding/src/lib.rs @@ -8,11 +8,11 @@ use crate::types::{ PublicKeyHashIdentityMap, }; use crate::util::{build_c_identity_struct, extract_vector_from_pointer, vec_to_pointer}; +use drive::drive::verify::AssetLockProof as DppAssetLockProof; use drive::drive::verify::Identity as DppIdentity; -use drive::drive::verify::{AssetLockProof as DppAssetLockProof}; use drive::drive::Drive; use std::collections::BTreeMap; -use std::{slice}; +use std::slice; #[no_mangle] pub unsafe extern "C" fn verify_full_identity_by_public_key_hash( diff --git a/packages/rs-drive-verify-c-binding/src/util.rs b/packages/rs-drive-verify-c-binding/src/util.rs index 3d8cf531096..1a0f6dee355 100644 --- a/packages/rs-drive-verify-c-binding/src/util.rs +++ b/packages/rs-drive-verify-c-binding/src/util.rs @@ -1,6 +1,4 @@ -use crate::types::{ - AssetLockProof, IdPublicKeyMap, Identity, IdentityPublicKey, MetaData, -}; +use crate::types::{AssetLockProof, IdPublicKeyMap, Identity, IdentityPublicKey, MetaData}; use crate::{DppAssetLockProof, DppIdentity}; use std::{mem, slice}; From d91f22e21c7e678892cdaf86ab67607e6a1aa9ae Mon Sep 17 00:00:00 2001 From: Anton Suprunchuk Date: Tue, 11 Apr 2023 21:49:43 +0700 Subject: [PATCH 3/6] fix comments --- .../state_transition/data_contract_update_transition/mod.rs | 2 -- .../rs-dpp/src/data_trigger/reward_share_data_triggers/mod.rs | 1 + 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/rs-dpp/src/data_contract/state_transition/data_contract_update_transition/mod.rs b/packages/rs-dpp/src/data_contract/state_transition/data_contract_update_transition/mod.rs index cc406d9a240..6d9dbdb1b1e 100644 --- a/packages/rs-dpp/src/data_contract/state_transition/data_contract_update_transition/mod.rs +++ b/packages/rs-dpp/src/data_contract/state_transition/data_contract_update_transition/mod.rs @@ -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 do it manually in `to_object()` and `to_json()` - // #[serde(skip_serializing)] pub data_contract: DataContract, pub signature_public_key_id: KeyID, pub signature: BinaryData, diff --git a/packages/rs-dpp/src/data_trigger/reward_share_data_triggers/mod.rs b/packages/rs-dpp/src/data_trigger/reward_share_data_triggers/mod.rs index 64404534f9c..083b00c0883 100644 --- a/packages/rs-dpp/src/data_trigger/reward_share_data_triggers/mod.rs +++ b/packages/rs-dpp/src/data_trigger/reward_share_data_triggers/mod.rs @@ -62,6 +62,7 @@ where .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?; // From 3181f547e2070372cf84cdb770897d0de2b422c1 Mon Sep 17 00:00:00 2001 From: Anton Suprunchuk Date: Tue, 11 Apr 2023 22:43:52 +0700 Subject: [PATCH 4/6] remove test comment --- .../calculate_state_transition_fee_from_operations_factory.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/rs-dpp/src/state_transition/fee/calculate_state_transition_fee_from_operations_factory.rs b/packages/rs-dpp/src/state_transition/fee/calculate_state_transition_fee_from_operations_factory.rs index 68602c5858f..59bcae604dd 100644 --- a/packages/rs-dpp/src/state_transition/fee/calculate_state_transition_fee_from_operations_factory.rs +++ b/packages/rs-dpp/src/state_transition/fee/calculate_state_transition_fee_from_operations_factory.rs @@ -128,9 +128,8 @@ mod test { assert_eq!(expected, result); } - // TODO(wasm-dpp): remove this test if we don't need id #[test] - fn failing_test_with_negative_credits() { + fn test_with_negative_credits() { // Set of operations that produced by Document Remove Transition let operations = vec![ Operation::PreCalculated(PreCalculatedOperation { From cdf9fd0232f9de30367ed1beb4309f131fe259a9 Mon Sep 17 00:00:00 2001 From: Anton Suprunchuk Date: Tue, 11 Apr 2023 23:01:18 +0700 Subject: [PATCH 5/6] make document types in data triggers into constants --- Cargo.lock | 13 ++++++++++ .../data_trigger/get_data_triggers_factory.rs | 25 +++++++++++-------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8375b19b443..1e55fa4ff70 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3479,12 +3479,25 @@ dependencies = [ "dpp", "itertools", "js-sys", + "log", "serde", "serde-wasm-bindgen", "serde_json", "thiserror", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-logger", + "web-sys", +] + +[[package]] +name = "wasm-logger" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "074649a66bb306c8f2068c9016395fa65d8e08d2affcbf95acf3c24c3ab19718" +dependencies = [ + "log", + "wasm-bindgen", "web-sys", ] diff --git a/packages/rs-dpp/src/data_trigger/get_data_triggers_factory.rs b/packages/rs-dpp/src/data_trigger/get_data_triggers_factory.rs index b40bb6f965e..8928d5068ac 100644 --- a/packages/rs-dpp/src/data_trigger/get_data_triggers_factory.rs +++ b/packages/rs-dpp/src/data_trigger/get_data_triggers_factory.rs @@ -15,6 +15,11 @@ use crate::{ use super::{DataTrigger, DataTriggerKind}; +pub const REWARD_SHARE_DOCUMENT_TYPE: &'static str = "rewardShare"; +pub const CONTACT_REQUEST_DOCUMENT_TYPE: &'static str = "contactRequest"; +pub const DOMAIN_DOCUMENT_TYPE: &'static str = "domain"; +pub const PREORDER_DOCUMENT_TYPE: &'static str = "preorder"; + /// returns Date Triggers filtered out by dataContractId, documentType, transactionAction pub fn get_data_triggers<'a>( data_contract_id: &'a Identifier, @@ -58,56 +63,56 @@ pub fn data_triggers() -> Result, ProtocolError> { let data_triggers = vec![ DataTrigger { data_contract_id: dpns_data_contract_id, - document_type: "domain".to_string(), + document_type: DOMAIN_DOCUMENT_TYPE.to_string(), transition_action: Action::Create, data_trigger_kind: DataTriggerKind::DataTriggerCreateDomain, top_level_identity: Some(dpns_owner_id), }, DataTrigger { data_contract_id: dpns_data_contract_id, - document_type: "domain".to_string(), + document_type: DOMAIN_DOCUMENT_TYPE.to_string(), transition_action: Action::Replace, data_trigger_kind: DataTriggerKind::DataTriggerReject, top_level_identity: None, }, DataTrigger { data_contract_id: dpns_data_contract_id, - document_type: "domain".to_string(), + document_type: DOMAIN_DOCUMENT_TYPE.to_string(), transition_action: Action::Delete, data_trigger_kind: DataTriggerKind::DataTriggerReject, top_level_identity: None, }, DataTrigger { data_contract_id: dpns_data_contract_id, - document_type: "preorder".to_string(), + document_type: PREORDER_DOCUMENT_TYPE.to_string(), transition_action: Action::Delete, data_trigger_kind: DataTriggerKind::DataTriggerReject, top_level_identity: None, }, DataTrigger { data_contract_id: dpns_data_contract_id, - document_type: "preorder".to_string(), + document_type: PREORDER_DOCUMENT_TYPE.to_string(), transition_action: Action::Delete, data_trigger_kind: DataTriggerKind::DataTriggerReject, top_level_identity: None, }, DataTrigger { data_contract_id: dashpay_data_contract_id, - document_type: "contactRequest".to_string(), + document_type: CONTACT_REQUEST_DOCUMENT_TYPE.to_string(), transition_action: Action::Create, data_trigger_kind: DataTriggerKind::CreateDataContractRequest, top_level_identity: None, }, DataTrigger { data_contract_id: dashpay_data_contract_id, - document_type: "contactRequest".to_string(), + document_type: CONTACT_REQUEST_DOCUMENT_TYPE.to_string(), transition_action: Action::Replace, data_trigger_kind: DataTriggerKind::DataTriggerReject, top_level_identity: None, }, DataTrigger { data_contract_id: dashpay_data_contract_id, - document_type: "contactRequest".to_string(), + document_type: CONTACT_REQUEST_DOCUMENT_TYPE.to_string(), transition_action: Action::Delete, data_trigger_kind: DataTriggerKind::DataTriggerReject, top_level_identity: None, @@ -135,14 +140,14 @@ pub fn data_triggers() -> Result, ProtocolError> { }, DataTrigger { data_contract_id: master_node_reward_shares_contract_id, - document_type: "rewardShare".to_string(), + document_type: REWARD_SHARE_DOCUMENT_TYPE.to_string(), transition_action: Action::Create, data_trigger_kind: DataTriggerKind::DataTriggerRewardShare, top_level_identity: None, }, DataTrigger { data_contract_id: master_node_reward_shares_contract_id, - document_type: "rewardShare".to_string(), + document_type: REWARD_SHARE_DOCUMENT_TYPE.to_string(), transition_action: Action::Replace, data_trigger_kind: DataTriggerKind::DataTriggerRewardShare, top_level_identity: None, From aaa6f797e3f430692b93fab0ed52e7d79a370119 Mon Sep 17 00:00:00 2001 From: Ivan Shumkov Date: Wed, 12 Apr 2023 16:10:54 +0800 Subject: [PATCH 6/6] test(drive): fix verify binding test --- .../lib/abci/handlers/prepareProposalHandlerFactory.js | 2 +- .../rs-dpp/src/data_trigger/get_data_triggers_factory.rs | 9 +++++---- packages/rs-drive-verify-c-binding/src/lib.rs | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/js-drive/lib/abci/handlers/prepareProposalHandlerFactory.js b/packages/js-drive/lib/abci/handlers/prepareProposalHandlerFactory.js index 9f36462f661..0faef989872 100644 --- a/packages/js-drive/lib/abci/handlers/prepareProposalHandlerFactory.js +++ b/packages/js-drive/lib/abci/handlers/prepareProposalHandlerFactory.js @@ -162,7 +162,7 @@ function prepareProposalHandlerFactory( invalidTxCount, mempoolTxCount, }, - `Prepared block proposal for height #${height} with appHash ${appHash.toString('hex').toUpperCase()}` + `Prepared proposal #${height} with appHash ${appHash.toString('hex').toUpperCase()}` + ` in ${roundExecutionTime} seconds (valid txs = ${validTxCount}, invalid txs = ${invalidTxCount}, mempool txs = ${mempoolTxCount})`, ); diff --git a/packages/rs-dpp/src/data_trigger/get_data_triggers_factory.rs b/packages/rs-dpp/src/data_trigger/get_data_triggers_factory.rs index 8928d5068ac..d01fbd163be 100644 --- a/packages/rs-dpp/src/data_trigger/get_data_triggers_factory.rs +++ b/packages/rs-dpp/src/data_trigger/get_data_triggers_factory.rs @@ -15,10 +15,11 @@ use crate::{ use super::{DataTrigger, DataTriggerKind}; -pub const REWARD_SHARE_DOCUMENT_TYPE: &'static str = "rewardShare"; -pub const CONTACT_REQUEST_DOCUMENT_TYPE: &'static str = "contactRequest"; -pub const DOMAIN_DOCUMENT_TYPE: &'static str = "domain"; -pub const PREORDER_DOCUMENT_TYPE: &'static str = "preorder"; +// TODO: Move to system contract crates +pub const REWARD_SHARE_DOCUMENT_TYPE: &str = "rewardShare"; +pub const CONTACT_REQUEST_DOCUMENT_TYPE: &str = "contactRequest"; +pub const DOMAIN_DOCUMENT_TYPE: &str = "domain"; +pub const PREORDER_DOCUMENT_TYPE: &str = "preorder"; /// returns Date Triggers filtered out by dataContractId, documentType, transactionAction pub fn get_data_triggers<'a>( diff --git a/packages/rs-drive-verify-c-binding/src/lib.rs b/packages/rs-drive-verify-c-binding/src/lib.rs index af767acdb12..047b90961cc 100644 --- a/packages/rs-drive-verify-c-binding/src/lib.rs +++ b/packages/rs-drive-verify-c-binding/src/lib.rs @@ -216,6 +216,7 @@ pub unsafe extern "C" fn verify_identity_ids_by_public_key_hashes( #[cfg(test)] mod tests { use super::*; + use drive::drive::verify::RootHash; use drive::drive::Drive; use std::collections::BTreeMap;