diff --git a/CHANGELOG.md b/CHANGELOG.md index 56f2d1568d1..330301fc6eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,12 @@ * **sdk:** user-friendly evo sdk params ([#2856](https://github.com/dashpay/platform/issues/2856)) * use identity contract keys query ([#2870](https://github.com/dashpay/platform/issues/2870)) +### [2.1.3](https://github.com/dashpay/platform/compare/v2.1.2...v2.1.3) (2025-10-29) + +### Bug Fixes + +* **drive:** reuse existing platform node id during operator update ([#2834](https://github.com/dashpay/platform/issues/2834)) + ### [2.1.2](https://github.com/dashpay/platform/compare/v2.1.1...v2.1.2) (2025-10-27) diff --git a/package.json b/package.json index 0afaf9ea5e8..bf06db90e90 100644 --- a/package.json +++ b/package.json @@ -115,4 +115,4 @@ "dompurify": "^3.2.6", "node-gyp": "^10.0.1" } -} +} \ No newline at end of file diff --git a/packages/bench-suite/package.json b/packages/bench-suite/package.json index 24773a0b4c0..d767700d600 100644 --- a/packages/bench-suite/package.json +++ b/packages/bench-suite/package.json @@ -56,4 +56,4 @@ "url": "https://github.com/dashevo/platform/issues" }, "homepage": "https://github.com/dashevo/platform#readme" -} +} \ No newline at end of file diff --git a/packages/dapi-grpc/package.json b/packages/dapi-grpc/package.json index abd43bf9144..5e69268a62c 100644 --- a/packages/dapi-grpc/package.json +++ b/packages/dapi-grpc/package.json @@ -64,4 +64,4 @@ "sinon": "^17.0.1", "sinon-chai": "^3.7.0" } -} +} \ No newline at end of file diff --git a/packages/dapi/package.json b/packages/dapi/package.json index d93c3f12953..a4fb28790a9 100644 --- a/packages/dapi/package.json +++ b/packages/dapi/package.json @@ -84,4 +84,4 @@ "url": "https://github.com/dashevo/dapi/issues" }, "homepage": "https://github.com/dashevo/dapi#readme" -} +} \ No newline at end of file diff --git a/packages/dash-spv/package.json b/packages/dash-spv/package.json index e50bf74dac2..178ff27d6f5 100644 --- a/packages/dash-spv/package.json +++ b/packages/dash-spv/package.json @@ -28,4 +28,4 @@ "should": "^13.2.3", "sinon": "^17.0.1" } -} +} \ No newline at end of file diff --git a/packages/dashmate/docs/services/platform.md b/packages/dashmate/docs/services/platform.md index 5b260011f35..99b046a9530 100644 --- a/packages/dashmate/docs/services/platform.md +++ b/packages/dashmate/docs/services/platform.md @@ -99,17 +99,17 @@ Tenderdash is the consensus engine that provides Byzantine Fault Tolerant (BFT) * Communicates with other Tenderdash nodes via P2P * Provides RPC for DAPI API -| Service | Port Purpose | Default Value | Config Path | Default Host Binding | Host Config Path | -|---------------------------|----------------------|---------------|--------------------------------------------------|---------------------|-----------------| -| **Drive ABCI** | ABCI | 26658 | (fixed internal) | (internal) | - | -| | gRPC | 26670 | (fixed internal) | (internal) | - | -| | Metrics | 29090 | (exposed via PLATFORM_DRIVE_ABCI_METRICS_PORT) | 127.0.0.1 (local) | PLATFORM_DRIVE_ABCI_METRICS_HOST | -| | Tokio Console | 6669 | `platform.drive.abci.tokioConsole.port` | 127.0.0.1 (local) | `platform.drive.abci.tokioConsole.host` | -| | GroveDB Visualizer | 8083 | `platform.drive.abci.grovedbVisualizer.port` | 127.0.0.1 (local) | `platform.drive.abci.grovedbVisualizer.host` | -| **Drive Tenderdash** | P2P | 26656 | `platform.drive.tenderdash.p2p.port` | 0.0.0.0 (all) | `platform.drive.tenderdash.p2p.host` | -| | RPC | 26657 | `platform.drive.tenderdash.rpc.port` | 127.0.0.1 (local) | `platform.drive.tenderdash.rpc.host` | -| | Metrics | 26660 | `platform.drive.tenderdash.metrics.port` | 127.0.0.1 (local) | `platform.drive.tenderdash.metrics.host` | -| | pprof Debug | 6060 | `platform.drive.tenderdash.pprof.port` | 127.0.0.1 (local) | (fixed) | +| Service | Port Purpose | Default Value | Config Path | Default Host Binding | Host Config Path | +| -------------------- | ------------------ | ------------- | ---------------------------------------------- | -------------------- | -------------------------------------------- | +| **Drive ABCI** | ABCI | 26658 | (fixed internal) | (internal) | - | +| | gRPC | 26670 | (fixed internal) | (internal) | - | +| | Metrics | 29090 | (exposed via PLATFORM_DRIVE_ABCI_METRICS_PORT) | 127.0.0.1 (local) | PLATFORM_DRIVE_ABCI_METRICS_HOST | +| | Tokio Console | 6669 | `platform.drive.abci.tokioConsole.port` | 127.0.0.1 (local) | `platform.drive.abci.tokioConsole.host` | +| | GroveDB Visualizer | 8083 | `platform.drive.abci.grovedbVisualizer.port` | 127.0.0.1 (local) | `platform.drive.abci.grovedbVisualizer.host` | +| **Drive Tenderdash** | P2P | 26656 | `platform.drive.tenderdash.p2p.port` | 0.0.0.0 (all) | `platform.drive.tenderdash.p2p.host` | +| | RPC | 26657 | `platform.drive.tenderdash.rpc.port` | 127.0.0.1 (local) | `platform.drive.tenderdash.rpc.host` | +| | Metrics | 26660 | `platform.drive.tenderdash.metrics.port` | 127.0.0.1 (local) | `platform.drive.tenderdash.metrics.host` | +| | pprof Debug | 6060 | `platform.drive.tenderdash.pprof.port` | 127.0.0.1 (local) | (fixed) | ## DAPI Services @@ -133,10 +133,10 @@ Tenderdash is the consensus engine that provides Byzantine Fault Tolerant (BFT) **rs-dapi Ports and Configuration**: -| Service | Port Purpose | Default Value | Config Path | Default Host Binding | Host Config Path | -|----------------------|------------------|---------------|-------------------------------------------------|----------------------|------------------| -| **rs-dapi (Rust)** | JSON-RPC | 3009 | (fixed internal) | (internal) | - | -| | gRPC / gRPC-Web | 3010 | (fixed internal) | (internal) | - | -| | Metrics & Health | 9091 (mainnet), 19091 (testnet), 29091 (local)| `platform.dapi.rsDapi.metrics.port` | 127.0.0.1 | `platform.dapi.rsDapi.metrics.host` | +| Service | Port Purpose | Default Value | Config Path | Default Host Binding | Host Config Path | +| ------------------ | ---------------- | ---------------------------------------------- | ----------------------------------- | -------------------- | ----------------------------------- | +| **rs-dapi (Rust)** | JSON-RPC | 3009 | (fixed internal) | (internal) | - | +| | gRPC / gRPC-Web | 3010 | (fixed internal) | (internal) | - | +| | Metrics & Health | 9091 (mainnet), 19091 (testnet), 29091 (local) | `platform.dapi.rsDapi.metrics.port` | 127.0.0.1 | `platform.dapi.rsDapi.metrics.host` | The rs-dapi metrics server exposes health endpoints alongside Prometheus data on `/metrics` from the same port. Dashmate applies network-specific defaults (mainnet 9091, testnet 19091, local 29091) so multiple presets can coexist on a host without conflicts. diff --git a/packages/dashmate/package.json b/packages/dashmate/package.json index 8d2ec0f6091..ef48acbcca6 100644 --- a/packages/dashmate/package.json +++ b/packages/dashmate/package.json @@ -166,4 +166,4 @@ }, "topicSeparator": " " } -} +} \ No newline at end of file diff --git a/packages/dashmate/src/config/getConfigProfilesFactory.js b/packages/dashmate/src/config/getConfigProfilesFactory.js index dfb9928fa29..888a1cf7e30 100644 --- a/packages/dashmate/src/config/getConfigProfilesFactory.js +++ b/packages/dashmate/src/config/getConfigProfilesFactory.js @@ -8,13 +8,27 @@ export default function getConfigProfilesFactory() { * @param {{ includeAll?: boolean }} [options] * @returns {string[]} */ - function getConfigProfiles(config) { + function getConfigProfiles(config, { includeAll = false } = {}) { const profiles = []; profiles.push('core'); if (config.get('platform.enable')) { profiles.push('platform'); + + // Config option 'platform.dapi.deprecated.enabled' was removed + const deprecatedEnabled = config.has('platform.dapi.deprecated.enabled') + ? config.get('platform.dapi.deprecated.enabled') + : false; + + if (includeAll) { + profiles.push('platform-dapi-deprecated'); + profiles.push('platform-dapi-rs'); + } else if (deprecatedEnabled) { + profiles.push('platform-dapi-deprecated'); + } else { + profiles.push('platform-dapi-rs'); + } } return Array.from(new Set(profiles)); diff --git a/packages/dashpay-contract/package.json b/packages/dashpay-contract/package.json index d41e2716327..94a2fac81e2 100644 --- a/packages/dashpay-contract/package.json +++ b/packages/dashpay-contract/package.json @@ -35,4 +35,4 @@ "sinon": "^17.0.1", "sinon-chai": "^3.7.0" } -} +} \ No newline at end of file diff --git a/packages/dpns-contract/package.json b/packages/dpns-contract/package.json index 839258bc370..21946ad226a 100644 --- a/packages/dpns-contract/package.json +++ b/packages/dpns-contract/package.json @@ -41,4 +41,4 @@ "sinon": "^17.0.1", "sinon-chai": "^3.7.0" } -} +} \ No newline at end of file diff --git a/packages/feature-flags-contract/package.json b/packages/feature-flags-contract/package.json index 5898b6f8caa..7aa296ce002 100644 --- a/packages/feature-flags-contract/package.json +++ b/packages/feature-flags-contract/package.json @@ -42,4 +42,4 @@ "sinon": "^17.0.1", "sinon-chai": "^3.7.0" } -} +} \ No newline at end of file diff --git a/packages/js-dapi-client/package.json b/packages/js-dapi-client/package.json index 3eb1ffdc802..af8f8d25ed3 100644 --- a/packages/js-dapi-client/package.json +++ b/packages/js-dapi-client/package.json @@ -102,4 +102,4 @@ ] }, "license": "MIT" -} +} \ No newline at end of file diff --git a/packages/js-dash-sdk/package.json b/packages/js-dash-sdk/package.json index e2d03ed16d5..faab9020915 100644 --- a/packages/js-dash-sdk/package.json +++ b/packages/js-dash-sdk/package.json @@ -109,4 +109,4 @@ "webpack": "^5.94.0", "webpack-cli": "^4.9.1" } -} +} \ No newline at end of file diff --git a/packages/js-evo-sdk/package.json b/packages/js-evo-sdk/package.json index 3dca1951fcd..8fb3c820b67 100644 --- a/packages/js-evo-sdk/package.json +++ b/packages/js-evo-sdk/package.json @@ -66,4 +66,4 @@ "webpack": "^5.94.0", "webpack-cli": "^4.9.1" } -} +} \ No newline at end of file diff --git a/packages/js-grpc-common/package.json b/packages/js-grpc-common/package.json index 26bac5c85ff..8318b9bba05 100644 --- a/packages/js-grpc-common/package.json +++ b/packages/js-grpc-common/package.json @@ -34,4 +34,4 @@ "long": "^5.2.0", "semver": "^7.5.3" } -} +} \ No newline at end of file diff --git a/packages/keyword-search-contract/package.json b/packages/keyword-search-contract/package.json index c98a888e4be..9e83938b8b6 100644 --- a/packages/keyword-search-contract/package.json +++ b/packages/keyword-search-contract/package.json @@ -26,4 +26,4 @@ "sinon": "^17.0.1", "sinon-chai": "^3.7.0" } -} +} \ No newline at end of file diff --git a/packages/masternode-reward-shares-contract/package.json b/packages/masternode-reward-shares-contract/package.json index 73d74417dde..1c305531998 100644 --- a/packages/masternode-reward-shares-contract/package.json +++ b/packages/masternode-reward-shares-contract/package.json @@ -41,4 +41,4 @@ "sinon": "^17.0.1", "sinon-chai": "^3.7.0" } -} +} \ No newline at end of file diff --git a/packages/platform-test-suite/package.json b/packages/platform-test-suite/package.json index 52ee43dae78..4e6572fbf72 100644 --- a/packages/platform-test-suite/package.json +++ b/packages/platform-test-suite/package.json @@ -81,4 +81,4 @@ "eslint-config-airbnb-base": "^15.0.0", "eslint-plugin-import": "^2.29.0" } -} +} \ No newline at end of file diff --git a/packages/rs-dash-event-bus/Cargo.toml b/packages/rs-dash-event-bus/Cargo.toml index 1eae3b9904e..ae2b4cd0c78 100644 --- a/packages/rs-dash-event-bus/Cargo.toml +++ b/packages/rs-dash-event-bus/Cargo.toml @@ -1,7 +1,8 @@ [package] + +edition = "2024" name = "rs-dash-event-bus" version.workspace = true -edition = "2024" license = "MIT" description = "Shared event bus and Platform events multiplexer for Dash Platform (rs-dapi, rs-drive-abci, rs-sdk)" diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs index 4da672daefd..3c78e6d4e1f 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_identities/update_operator_identity/v0/mod.rs @@ -355,12 +355,7 @@ where purpose: Purpose::SYSTEM, security_level: SecurityLevel::CRITICAL, read_only: true, - data: BinaryData::new( - platform_node_id_change - .as_ref() - .expect("platform node id confirmed is some") - .to_vec(), - ), + data: BinaryData::new(new_platform_node_id.to_vec()), disabled_at: None, contract_bounds: None, } @@ -403,6 +398,8 @@ mod tests { use dpp::dashcore_rpc::dashcore_rpc_json::{MasternodeListItem, MasternodeType}; use dpp::dashcore_rpc::json::DMNState; use dpp::identifier::MasternodeIdentifiers; + use dpp::identity::accessors::IdentityGettersV0; + use dpp::identity::identity_public_key::accessors::v0::IdentityPublicKeyGettersV0; use dpp::identity::identity_public_key::v0::IdentityPublicKeyV0; use dpp::identity::{IdentityV0, KeyType, Purpose, SecurityLevel}; use dpp::platform_value::BinaryData; @@ -1023,6 +1020,145 @@ mod tests { .expect("expected to apply drive operations"); } + #[test] + fn test_update_operator_identity_reuses_node_id_without_change() { + let platform_version = PlatformVersion::latest(); + let platform = TestPlatformBuilder::new() + .build_with_mock_rpc() + .set_genesis_state(); + + let block_info = BlockInfo::default(); + + let mut rng = StdRng::seed_from_u64(5); + + let ( + pro_tx_hash, + _identity, + operator_payout_address, + original_pub_key_operator, + node_id_bytes, + ) = create_operator_identity(&platform, &mut rng); + + // Pre-create an operator identity for the new operator key that lacks the platform node key + let private_key_operator_bytes = bls_signatures::PrivateKey::generate_dash(&mut rng) + .expect("expected to generate a private key") + .to_bytes() + .to_vec(); + let private_key_operator = BlsPrivateKey::::from_be_bytes( + &private_key_operator_bytes + .try_into() + .expect("expected the secret key to be 32 bytes"), + ) + .expect( + "expected the conversion between bls signatures library and blsful to happen without failing", + ); + let new_pub_key_operator = private_key_operator.public_key().0.to_compressed().to_vec(); + + let new_operator_identifier = Identifier::create_operator_identifier( + pro_tx_hash.as_byte_array(), + &new_pub_key_operator, + ); + + let operator_key_without_node_id: IdentityPublicKey = IdentityPublicKeyV0 { + id: 0, + key_type: KeyType::BLS12_381, + purpose: Purpose::SYSTEM, + security_level: SecurityLevel::CRITICAL, + read_only: true, + data: BinaryData::new(new_pub_key_operator.clone()), + disabled_at: None, + contract_bounds: None, + } + .into(); + + let mut identity_without_node_id = + Identity::create_basic_identity(new_operator_identifier, platform_version) + .expect("expected to create identity"); + identity_without_node_id.add_public_keys(vec![operator_key_without_node_id]); + + platform + .drive + .add_new_identity( + identity_without_node_id, + true, + &block_info, + true, + None, + platform_version, + ) + .expect("expected to add pre-existing operator identity"); + + // Create an old masternode state with the original operator key and node id + let masternode_list_item = MasternodeListItem { + node_type: MasternodeType::Regular, + pro_tx_hash, + collateral_hash: Txid::from_byte_array(rng.gen::<[u8; 32]>()), + collateral_index: 0, + collateral_address: [0; 20], + operator_reward: 0.0, + state: DMNState { + service: SocketAddr::from_str("1.0.1.1:1234").unwrap(), + registered_height: 0, + pose_revived_height: None, + pose_ban_height: None, + revocation_reason: 0, + owner_address: rng.gen::<[u8; 20]>(), + voting_address: rng.gen::<[u8; 20]>(), + payout_address: rng.gen::<[u8; 20]>(), + pub_key_operator: original_pub_key_operator.clone(), + operator_payout_address: Some(operator_payout_address), + platform_node_id: Some(node_id_bytes), + platform_p2p_port: None, + platform_http_port: None, + }, + }; + + let mut platform_state = platform.state.load().clone().deref().clone(); + platform_state + .full_masternode_list_mut() + .insert(pro_tx_hash, masternode_list_item); + + let transaction = platform.drive.grove.start_transaction(); + + let mut drive_operations = vec![]; + + platform + .update_operator_identity_v0( + &pro_tx_hash, + Some(&new_pub_key_operator), + None, + None, + &platform_state, + &transaction, + &mut drive_operations, + platform_version, + ) + .expect("expected to update operator identity without panic"); + + let expected_identity_bytes = new_operator_identifier.to_buffer(); + let expected_node_id = node_id_bytes.to_vec(); + + let added_platform_node_key = drive_operations.iter().any(|operation| { + if let drive::util::batch::DriveOperation::IdentityOperation( + drive::util::batch::IdentityOperationType::AddNewKeysToIdentity { + identity_id, + non_unique_keys_to_add, + .. + }, + ) = operation + { + if identity_id == &expected_identity_bytes { + return non_unique_keys_to_add + .iter() + .any(|key| key.data().as_slice() == expected_node_id.as_slice()); + } + } + false + }); + + assert!(added_platform_node_key); + } + #[test] fn test_update_operator_change_back_to_previous_public_key() { let platform_version = PlatformVersion::latest(); diff --git a/packages/token-history-contract/package.json b/packages/token-history-contract/package.json index 9f4c297ff4d..c6f89670aa5 100644 --- a/packages/token-history-contract/package.json +++ b/packages/token-history-contract/package.json @@ -26,4 +26,4 @@ "sinon": "^17.0.1", "sinon-chai": "^3.7.0" } -} +} \ No newline at end of file diff --git a/packages/wallet-lib/package.json b/packages/wallet-lib/package.json index f2a49a1697f..3faca309bf5 100644 --- a/packages/wallet-lib/package.json +++ b/packages/wallet-lib/package.json @@ -98,4 +98,4 @@ "webpack": "^5.94.0", "webpack-cli": "^4.9.1" } -} +} \ No newline at end of file diff --git a/packages/wallet-utils-contract/package.json b/packages/wallet-utils-contract/package.json index 75e0be3b68b..ad80af61fa4 100644 --- a/packages/wallet-utils-contract/package.json +++ b/packages/wallet-utils-contract/package.json @@ -26,4 +26,4 @@ "sinon": "^17.0.1", "sinon-chai": "^3.7.0" } -} +} \ No newline at end of file diff --git a/packages/wasm-dpp/package.json b/packages/wasm-dpp/package.json index 31ceee0acd3..50d933a5682 100644 --- a/packages/wasm-dpp/package.json +++ b/packages/wasm-dpp/package.json @@ -89,4 +89,4 @@ "webpack": "^5.94.0", "webpack-cli": "^4.9.1" } -} +} \ No newline at end of file diff --git a/packages/wasm-drive-verify/package.json b/packages/wasm-drive-verify/package.json index a57b33c31d7..f218787d119 100644 --- a/packages/wasm-drive-verify/package.json +++ b/packages/wasm-drive-verify/package.json @@ -56,4 +56,4 @@ "build": "./build.sh", "build:modules": "./scripts/build-modules.sh" } -} +} \ No newline at end of file diff --git a/packages/wasm-sdk/package.json b/packages/wasm-sdk/package.json index 20f2a62701d..354a6c7a522 100644 --- a/packages/wasm-sdk/package.json +++ b/packages/wasm-sdk/package.json @@ -67,4 +67,4 @@ "webpack": "^5.94.0", "webpack-cli": "^4.9.1" } -} +} \ No newline at end of file diff --git a/packages/withdrawals-contract/package.json b/packages/withdrawals-contract/package.json index 6c18b7db5db..7ab8f082152 100644 --- a/packages/withdrawals-contract/package.json +++ b/packages/withdrawals-contract/package.json @@ -42,4 +42,4 @@ "sinon": "^17.0.1", "sinon-chai": "^3.7.0" } -} +} \ No newline at end of file