diff --git a/.github/actions/rust/action.yaml b/.github/actions/rust/action.yaml index a6aa86446e0..4965f7721a9 100644 --- a/.github/actions/rust/action.yaml +++ b/.github/actions/rust/action.yaml @@ -5,7 +5,7 @@ inputs: toolchain: description: Rust toolchain to use, stable / nightly / beta, or exact version # The same as in /README.md - default: "stable" + default: "1.76" target: description: Target Rust platform required: false diff --git a/.github/workflows/tests-rs-package.yml b/.github/workflows/tests-rs-package.yml index 77e28b2232f..2cf0b636d12 100644 --- a/.github/workflows/tests-rs-package.yml +++ b/.github/workflows/tests-rs-package.yml @@ -73,7 +73,7 @@ jobs: cache: false - name: Check formatting - run: exit `cargo fmt --check --package=${{ inputs.package }} | wc -l` + run: cargo fmt --check --package=${{ inputs.package }} unused_deps: name: Unused dependencies diff --git a/Cargo.lock b/Cargo.lock index 19c63f23809..f5e046b964f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1653,6 +1653,7 @@ dependencies = [ "dotenvy", "dpp", "drive", + "drive-abci", "envy", "file-rotate", "hex", diff --git a/packages/dashmate/configs/defaults/getBaseConfigFactory.js b/packages/dashmate/configs/defaults/getBaseConfigFactory.js index 9459d657db5..f52fa4ab2ed 100644 --- a/packages/dashmate/configs/defaults/getBaseConfigFactory.js +++ b/packages/dashmate/configs/defaults/getBaseConfigFactory.js @@ -15,7 +15,8 @@ import semver from 'semver'; import fs from 'fs'; import { - NETWORK_TESTNET, PACKAGE_ROOT_DIR, + NETWORK_MAINNET, + PACKAGE_ROOT_DIR, } from '../../src/constants.js'; import Config from '../../src/config/Config.js'; @@ -245,12 +246,28 @@ export default function getBaseConfigFactory(homeDir) { retention: 60 * 3, }, validatorSet: { - llmqType: 4, + quorum: { + llmqType: 4, + dkgInterval: 24, + activeSigners: 24, + rotation: false, + }, }, chainLock: { - llmqType: 2, - dkgInterval: 288, - llmqSize: 400, + quorum: { + llmqType: 2, + dkgInterval: 288, + activeSigners: 4, + rotation: false, + }, + }, + instantLock: { + quorum: { + llmqType: 5, + dkgInterval: 288, + activeSigners: 32, + rotation: true, + }, }, metrics: { enabled: false, @@ -425,7 +442,7 @@ export default function getBaseConfigFactory(homeDir) { }, }, externalIp: null, - network: NETWORK_TESTNET, + network: NETWORK_MAINNET, environment: 'production', }; diff --git a/packages/dashmate/configs/defaults/getLocalConfigFactory.js b/packages/dashmate/configs/defaults/getLocalConfigFactory.js index 33992ceceb7..6148abbf866 100644 --- a/packages/dashmate/configs/defaults/getLocalConfigFactory.js +++ b/packages/dashmate/configs/defaults/getLocalConfigFactory.js @@ -70,12 +70,28 @@ export default function getLocalConfigFactory(getBaseConfig) { }, abci: { validatorSet: { - llmqType: 106, + quorum: { + llmqType: 106, + dkgInterval: 24, + activeSigners: 2, + rotation: false, + }, }, chainLock: { - llmqType: 100, - dkgInterval: 24, - llmqSize: 3, + quorum: { + llmqType: 100, + dkgInterval: 24, + activeSigners: 2, + rotation: false, + }, + }, + instantLock: { + quorum: { + llmqType: 104, + dkgInterval: 24, + activeSigners: 2, + rotation: false, + }, }, }, }, diff --git a/packages/dashmate/configs/defaults/getTestnetConfigFactory.js b/packages/dashmate/configs/defaults/getTestnetConfigFactory.js index 323d63314bb..59210678ce1 100644 --- a/packages/dashmate/configs/defaults/getTestnetConfigFactory.js +++ b/packages/dashmate/configs/defaults/getTestnetConfigFactory.js @@ -55,12 +55,28 @@ export default function getTestnetConfigFactory(homeDir, getBaseConfig) { abci: { epochTime: 3600, validatorSet: { - llmqType: 6, + quorum: { + llmqType: 6, + dkgInterval: 24, + activeSigners: 24, + rotation: false, + }, }, chainLock: { - llmqType: 1, - dkgInterval: 24, - llmqSize: 50, + quorum: { + llmqType: 1, + dkgInterval: 24, + activeSigners: 24, + rotation: false, + }, + }, + instantLock: { + quorum: { + llmqType: 5, + dkgInterval: 288, + activeSigners: 32, + rotation: true, + }, }, }, tenderdash: { diff --git a/packages/dashmate/configs/getConfigFileMigrationsFactory.js b/packages/dashmate/configs/getConfigFileMigrationsFactory.js index cdd3cd9405f..664f9bcf3d8 100644 --- a/packages/dashmate/configs/getConfigFileMigrationsFactory.js +++ b/packages/dashmate/configs/getConfigFileMigrationsFactory.js @@ -40,6 +40,20 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) return defaultConfigs.get(baseConfigName); } + function getDefaultConfigByNetwork(network) { + if (network === NETWORK_MAINNET) { + return defaultConfigs.get('mainnet'); + } + if (network === NETWORK_TESTNET) { + return defaultConfigs.get('testnet'); + } + if (network === NETWORK_LOCAL) { + return defaultConfigs.get('local'); + } + + return defaultConfigs.get('base'); + } + return { '0.24.0': (configFile) => { Object.entries(configFile.configs) @@ -613,6 +627,46 @@ export default function getConfigFileMigrationsFactory(homeDir, defaultConfigs) return configFile; }, + '1.0.0-dev.16': (configFile) => { + Object.entries(configFile.configs) + .forEach(([name, options]) => { + if (name === 'base') { + options.network = NETWORK_MAINNET; + } + + const networkConfig = getDefaultConfigByNetwork(options.network); + + options.platform.drive.abci.chainLock.quorum = { + llmqType: networkConfig.get('platform.drive.abci.chainLock.quorum.llmqType'), + dkgInterval: networkConfig.get('platform.drive.abci.chainLock.quorum.dkgInterval'), + activeSigners: networkConfig.get('platform.drive.abci.chainLock.quorum.activeSigners'), + rotation: networkConfig.get('platform.drive.abci.chainLock.quorum.rotation'), + }; + + delete options.platform.drive.abci.chainLock.llmqType; + delete options.platform.drive.abci.chainLock.llmqSize; + delete options.platform.drive.abci.chainLock.dkgInterval; + + options.platform.drive.abci.validatorSet.quorum = { + llmqType: networkConfig.get('platform.drive.abci.validatorSet.quorum.llmqType'), + dkgInterval: networkConfig.get('platform.drive.abci.validatorSet.quorum.dkgInterval'), + activeSigners: networkConfig.get('platform.drive.abci.validatorSet.quorum.activeSigners'), + rotation: networkConfig.get('platform.drive.abci.validatorSet.quorum.rotation'), + }; + + delete options.platform.drive.abci.validatorSet.llmqType; + + options.platform.drive.abci.instantLock = { + quorum: { + llmqType: networkConfig.get('platform.drive.abci.instantLock.quorum.llmqType'), + dkgInterval: networkConfig.get('platform.drive.abci.instantLock.quorum.dkgInterval'), + activeSigners: networkConfig.get('platform.drive.abci.instantLock.quorum.activeSigners'), + rotation: networkConfig.get('platform.drive.abci.instantLock.quorum.rotation'), + }, + }; + }); + return configFile; + }, }; } diff --git a/packages/dashmate/docker-compose.yml b/packages/dashmate/docker-compose.yml index e4782168e48..3d41a95ecd6 100644 --- a/packages/dashmate/docker-compose.yml +++ b/packages/dashmate/docker-compose.yml @@ -65,10 +65,18 @@ services: - MASTERNODE_REWARD_SHARES_SECOND_PUBLIC_KEY=${PLATFORM_MASTERNODE_REWARD_SHARES_SECOND_PUBLIC_KEY} - WITHDRAWALS_MASTER_PUBLIC_KEY=${PLATFORM_WITHDRAWALS_MASTER_PUBLIC_KEY} - WITHDRAWALS_SECOND_PUBLIC_KEY=${PLATFORM_WITHDRAWALS_SECOND_PUBLIC_KEY} - - VALIDATOR_SET_QUORUM_TYPE=${PLATFORM_DRIVE_ABCI_VALIDATOR_SET_LLMQ_TYPE:?err} - - CHAIN_LOCK_QUORUM_TYPE=${PLATFORM_DRIVE_ABCI_CHAIN_LOCK_LLMQ_TYPE:?err} - - CHAIN_LOCK_QUORUM_WINDOW=${PLATFORM_DRIVE_ABCI_CHAIN_LOCK_DKG_INTERVAL:?err} - - CHAIN_LOCK_QUORUM_SIZE=${PLATFORM_DRIVE_ABCI_CHAIN_LOCK_LLMQ_SIZE:?err} + - VALIDATOR_SET_QUORUM_TYPE=${PLATFORM_DRIVE_ABCI_VALIDATOR_SET_QUORUM_LLMQ_TYPE:?err} + - VALIDATOR_SET_QUORUM_WINDOW=${PLATFORM_DRIVE_ABCI_VALIDATOR_SET_QUORUM_DKG_INTERVAL:?err} + - VALIDATOR_SET_QUORUM_ACTIVE_SIGNERS=${PLATFORM_DRIVE_ABCI_VALIDATOR_SET_QUORUM_ACTIVE_SIGNERS:?err} + - VALIDATOR_SET_QUORUM_ROTATION=${PLATFORM_DRIVE_ABCI_VALIDATOR_SET_QUORUM_ROTATION:?err} + - CHAIN_LOCK_QUORUM_TYPE=${PLATFORM_DRIVE_ABCI_CHAIN_LOCK_QUORUM_LLMQ_TYPE:?err} + - CHAIN_LOCK_QUORUM_WINDOW=${PLATFORM_DRIVE_ABCI_CHAIN_LOCK_QUORUM_DKG_INTERVAL:?err} + - CHAIN_LOCK_QUORUM_ACTIVE_SIGNERS=${PLATFORM_DRIVE_ABCI_CHAIN_LOCK_QUORUM_ACTIVE_SIGNERS:?err} + - CHAIN_LOCK_QUORUM_ROTATION=${PLATFORM_DRIVE_ABCI_CHAIN_LOCK_QUORUM_ROTATION:?err} + - INSTANT_LOCK_QUORUM_TYPE=${PLATFORM_DRIVE_ABCI_INSTANT_LOCK_QUORUM_LLMQ_TYPE:?err} + - INSTANT_LOCK_QUORUM_WINDOW=${PLATFORM_DRIVE_ABCI_INSTANT_LOCK_QUORUM_DKG_INTERVAL:?err} + - INSTANT_LOCK_QUORUM_ACTIVE_SIGNERS=${PLATFORM_DRIVE_ABCI_INSTANT_LOCK_QUORUM_ACTIVE_SIGNERS:?err} + - INSTANT_LOCK_QUORUM_ROTATION=${PLATFORM_DRIVE_ABCI_INSTANT_LOCK_QUORUM_ROTATION:?err} - DB_PATH=/var/lib/dash/rs-drive-abci/db - ABCI_CONSENSUS_BIND_ADDRESS=tcp://0.0.0.0:26658 - GRPC_BIND_ADDRESS=0.0.0.0:26670 diff --git a/packages/dashmate/src/config/configJsonSchema.js b/packages/dashmate/src/config/configJsonSchema.js index b003a4aded4..d2633953cb2 100644 --- a/packages/dashmate/src/config/configJsonSchema.js +++ b/packages/dashmate/src/config/configJsonSchema.js @@ -105,6 +105,28 @@ export default { additionalProperties: false, required: ['enabled', 'host', 'port'], }, + quorum: { + type: 'object', + properties: { + llmqType: { + type: 'integer', + enum: [1, 2, 3, 4, 5, 6, 100, 101, 102, 103, 104, 105, 106, 107], + }, + dkgInterval: { + type: 'integer', + minimum: 1, + }, + activeSigners: { + type: 'integer', + minimum: 1, + }, + rotation: { + type: 'boolean', + }, + }, + required: ['llmqType', 'dkgInterval', 'activeSigners', 'rotation'], + additionalProperties: false, + }, }, properties: { description: { @@ -766,34 +788,32 @@ export default { validatorSet: { type: 'object', properties: { - llmqType: { - type: 'number', - // https://github.com/dashpay/dashcore-lib/blob/843176fed9fc81feae43ccf319d99e2dd942fe1f/lib/constants/index.js#L50-L99 - enum: [1, 2, 3, 4, 5, 6, 100, 101, 102, 103, 104, 105, 106, 107], + quorum: { + $ref: '#/definitions/quorum', }, }, additionalProperties: false, - required: ['llmqType'], + required: ['quorum'], }, chainLock: { type: 'object', properties: { - llmqType: { - type: 'number', - // https://github.com/dashpay/dashcore-lib/blob/843176fed9fc81feae43ccf319d99e2dd942fe1f/lib/constants/index.js#L50-L99 - enum: [1, 2, 3, 4, 5, 6, 100, 101, 102, 103, 104, 105, 106, 107], - }, - llmqSize: { - type: 'integer', - minimum: 0, + quorum: { + $ref: '#/definitions/quorum', }, - dkgInterval: { - type: 'integer', - minimum: 0, + }, + additionalProperties: false, + required: ['quorum'], + }, + instantLock: { + type: 'object', + properties: { + quorum: { + $ref: '#/definitions/quorum', }, }, additionalProperties: false, - required: ['llmqType', 'llmqSize', 'dkgInterval'], + required: ['quorum'], }, epochTime: { type: 'integer', diff --git a/packages/dashmate/src/listr/tasks/setup/local/configureTenderdashTaskFactory.js b/packages/dashmate/src/listr/tasks/setup/local/configureTenderdashTaskFactory.js index af533570888..da5e7e66fc0 100644 --- a/packages/dashmate/src/listr/tasks/setup/local/configureTenderdashTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/setup/local/configureTenderdashTaskFactory.js @@ -50,7 +50,7 @@ export default function configureTenderdashTaskFactory() { config.set( 'platform.drive.tenderdash.genesis.validator_quorum_type', - config.get('platform.drive.abci.validatorSet.llmqType'), + config.get('platform.drive.abci.validatorSet.quorum.llmqType'), ); }); }, diff --git a/packages/dashmate/src/listr/tasks/setup/local/enableCoreQuorumsTaskFactory.js b/packages/dashmate/src/listr/tasks/setup/local/enableCoreQuorumsTaskFactory.js index 9dd3f68699a..49fbbd47379 100644 --- a/packages/dashmate/src/listr/tasks/setup/local/enableCoreQuorumsTaskFactory.js +++ b/packages/dashmate/src/listr/tasks/setup/local/enableCoreQuorumsTaskFactory.js @@ -268,7 +268,7 @@ export default function enableCoreQuorumsTaskFactory(generateBlocks) { // eslint-disable-next-line prefer-destructuring ctx.quorumHash = quorumList[LLMQ_TYPE_TEST_PLATFORM][0]; - const llmqType = ctx.masternodeCoreServices[0].getConfig().get('platform.drive.abci.validatorSet.llmqType'); + const llmqType = ctx.masternodeCoreServices[0].getConfig().get('platform.drive.abci.validatorSet.quorum.llmqType'); const { result: quorumInfo } = await ctx.seedRpcClient.quorum('info', llmqType, ctx.quorumHash); diff --git a/packages/dashmate/test/unit/commands/config/set.spec.js b/packages/dashmate/test/unit/commands/config/set.spec.js index 94089cb9a77..67b8bef75a3 100644 --- a/packages/dashmate/test/unit/commands/config/set.spec.js +++ b/packages/dashmate/test/unit/commands/config/set.spec.js @@ -42,18 +42,18 @@ describe('Config set command', () => { const command = new ConfigSetCommand(); await command.runWithDependencies({ - option: 'platform.drive.abci.validatorSet.llmqType', + option: 'platform.drive.abci.validatorSet.quorum.llmqType', value: 107, }, flags, config); - expect(config.get('platform.drive.abci.validatorSet.llmqType')).to.equal(107); + expect(config.get('platform.drive.abci.validatorSet.quorum.llmqType')).to.equal(107); await command.runWithDependencies({ - option: 'platform.drive.abci.validatorSet.llmqType', + option: 'platform.drive.abci.validatorSet.quorum.llmqType', value: '107', }, flags, config); - expect(config.get('platform.drive.abci.validatorSet.llmqType')).to.equal(107); + expect(config.get('platform.drive.abci.validatorSet.quorum.llmqType')).to.equal(107); }); it('should allow setting booleans', async () => { diff --git a/packages/rs-dpp/src/errors/consensus/basic/identity/invalid_instant_asset_lock_proof_signature_error.rs b/packages/rs-dpp/src/errors/consensus/basic/identity/invalid_instant_asset_lock_proof_signature_error.rs index 130349d16a8..8d72de7772b 100644 --- a/packages/rs-dpp/src/errors/consensus/basic/identity/invalid_instant_asset_lock_proof_signature_error.rs +++ b/packages/rs-dpp/src/errors/consensus/basic/identity/invalid_instant_asset_lock_proof_signature_error.rs @@ -18,7 +18,7 @@ use bincode::{Decode, Encode}; PlatformSerialize, PlatformDeserialize, )] -#[error("Invalid instant lock proof signature")] +#[error("Instant lock proof signature is invalid or wasn't created recently. Pleases try chain asset lock proof instead.")] #[platform_serialize(unversioned)] pub struct InvalidInstantAssetLockProofSignatureError; diff --git a/packages/rs-drive-abci/.env.local b/packages/rs-drive-abci/.env.local index 942707ab200..739b5b8d214 100644 --- a/packages/rs-drive-abci/.env.local +++ b/packages/rs-drive-abci/.env.local @@ -28,13 +28,24 @@ CORE_JSON_RPC_PASSWORD=password INITIAL_CORE_CHAINLOCKED_HEIGHT=1243 # https://github.com/dashevo/dashcore-lib/blob/286c33a9d29d33f05d874c47a9b33764a0be0cf1/lib/constants/index.js#L42-L57 -VALIDATOR_SET_QUORUM_TYPE=llmq_test +VALIDATOR_SET_QUORUM_TYPE=llmq_test_platform VALIDATOR_SET_QUORUM_SIZE=3 +VALIDATOR_SET_QUORUM_WINDOW=24 +VALIDATOR_SET_QUORUM_ACTIVE_SIGNERS=2 +VALIDATOR_SET_QUORUM_ROTATION=false VALIDATOR_SET_ROTATION_BLOCK_COUNT=64 CHAIN_LOCK_QUORUM_TYPE=llmq_test -CHAIN_LOCK_QUORUM_WINDOW=24 CHAIN_LOCK_QUORUM_SIZE=3 +CHAIN_LOCK_QUORUM_WINDOW=24 +CHAIN_LOCK_QUORUM_ACTIVE_SIGNERS=2 +CHAIN_LOCK_QUORUM_ROTATION=false + +INSTANT_LOCK_QUORUM_TYPE=llmq_test_instantsend +INSTANT_LOCK_QUORUM_SIZE=3 +INSTANT_LOCK_QUORUM_WINDOW=24 +INSTANT_LOCK_QUORUM_ACTIVE_SIGNERS=2 +INSTANT_LOCK_QUORUM_ROTATION=false # DPNS Contract diff --git a/packages/rs-drive-abci/.env.mainnet b/packages/rs-drive-abci/.env.mainnet index a15602a413f..8e7f40cff51 100644 --- a/packages/rs-drive-abci/.env.mainnet +++ b/packages/rs-drive-abci/.env.mainnet @@ -30,10 +30,22 @@ INITIAL_CORE_CHAINLOCKED_HEIGHT=1243 # https://github.com/dashevo/dashcore-lib/blob/286c33a9d29d33f05d874c47a9b33764a0be0cf1/lib/constants/index.js#L42-L57 VALIDATOR_SET_QUORUM_TYPE=llmq_100_67 VALIDATOR_SET_QUORUM_SIZE=100 +VALIDATOR_SET_QUORUM_WINDOW=24 +VALIDATOR_SET_QUORUM_ACTIVE_SIGNERS=24 +VALIDATOR_SET_QUORUM_ROTATION=false VALIDATOR_SET_ROTATION_BLOCK_COUNT=64 CHAIN_LOCK_QUORUM_TYPE=llmq_400_60 +CHAIN_LOCK_QUORUM_SIZE=400 CHAIN_LOCK_QUORUM_WINDOW=288 +CHAIN_LOCK_QUORUM_ACTIVE_SIGNERS=4 +CHAIN_LOCK_QUORUM_ROTATION=false + +INSTANT_LOCK_QUORUM_TYPE=llmq_60_75 +INSTANT_LOCK_QUORUM_SIZE=60 +INSTANT_LOCK_QUORUM_WINDOW=288 +INSTANT_LOCK_QUORUM_ACTIVE_SIGNERS=32 +INSTANT_LOCK_QUORUM_ROTATION=true # DPNS Contract diff --git a/packages/rs-drive-abci/.env.testnet b/packages/rs-drive-abci/.env.testnet index e40ea7efc00..f0e6abf52ea 100644 --- a/packages/rs-drive-abci/.env.testnet +++ b/packages/rs-drive-abci/.env.testnet @@ -30,10 +30,22 @@ INITIAL_CORE_CHAINLOCKED_HEIGHT=1243 # https://github.com/dashevo/dashcore-lib/blob/286c33a9d29d33f05d874c47a9b33764a0be0cf1/lib/constants/index.js#L42-L57 VALIDATOR_SET_QUORUM_TYPE=llmq_25_67 VALIDATOR_SET_QUORUM_SIZE=25 +VALIDATOR_SET_QUORUM_WINDOW=24 +VALIDATOR_SET_QUORUM_ACTIVE_SIGNERS=24 +VALIDATOR_SET_QUORUM_ROTATION=false VALIDATOR_SET_ROTATION_BLOCK_COUNT=64 CHAIN_LOCK_QUORUM_TYPE=llmq_50_60 +CHAIN_LOCK_QUORUM_SIZE=50 CHAIN_LOCK_QUORUM_WINDOW=24 +CHAIN_LOCK_QUORUM_ACTIVE_SIGNERS=24 +CHAIN_LOCK_QUORUM_ROTATION=false + +INSTANT_LOCK_QUORUM_TYPE=llmq_60_75 +INSTANT_LOCK_QUORUM_SIZE=50 +INSTANT_LOCK_QUORUM_WINDOW=288 +INSTANT_LOCK_QUORUM_ACTIVE_SIGNERS=32 +INSTANT_LOCK_QUORUM_ROTATION=true # DPNS Contract diff --git a/packages/rs-drive-abci/Cargo.toml b/packages/rs-drive-abci/Cargo.toml index 8b1281b271e..eb01bfd39d8 100644 --- a/packages/rs-drive-abci/Cargo.toml +++ b/packages/rs-drive-abci/Cargo.toml @@ -99,6 +99,7 @@ dpp = { path = "../rs-dpp", features = [ drive = { path = "../rs-drive" } strategy-tests = { path = "../strategy-tests" } assert_matches = "1.5.0" +drive-abci = { path = ".", features = ["testing-config"]} # For tests of grovedb verify rocksdb = { version = "0.22.0" } @@ -109,7 +110,7 @@ integer-encoding = { version = "4.0.0" } default = ["mocks", "console"] mocks = ["mockall", "drive/fixtures-and-mocks"] console = ["console-subscriber", "tokio/tracing"] - +testing-config = [] [[bin]] name = "drive-abci" diff --git a/packages/rs-drive-abci/src/config.rs b/packages/rs-drive-abci/src/config.rs index e3d043d479e..23846e41e5c 100644 --- a/packages/rs-drive-abci/src/config.rs +++ b/packages/rs-drive-abci/src/config.rs @@ -26,6 +26,7 @@ // IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +use bincode::{Decode, Encode}; use dashcore_rpc::json::QuorumType; use std::path::PathBuf; @@ -98,6 +99,7 @@ pub struct ExecutionConfig { #[serde(default = "ExecutionConfig::default_verify_sum_trees")] pub verify_sum_trees: bool, + // TODO: Move to ValidatorSetConfig /// How often should quorums change? #[serde( default = "ExecutionConfig::default_validator_set_rotation_block_count", @@ -175,21 +177,16 @@ pub struct PlatformConfig { pub execution: ExecutionConfig, /// The default quorum type - pub validator_set_quorum_type: String, - - /// The quorum type used for verifying chain locks - pub chain_lock_quorum_type: String, - - /// The validator set quorum size - pub validator_set_quorum_size: u16, + #[serde(flatten)] + pub validator_set: ValidatorSetConfig, - /// The chain lock quorum size - pub chain_lock_quorum_size: u16, + /// Chain lock configuration + #[serde(flatten)] + pub chain_lock: ChainLockConfig, - /// The window for chain locks - /// On Mainnet Chain Locks are signed using 400_60: One quorum in every 288 blocks and activeQuorumCount is 4. - /// On Testnet Chain Locks are signed using 50_60: One quorum in every 24 blocks and activeQuorumCount is 24. - pub chain_lock_quorum_window: u32, + /// Instant lock configuration + #[serde(flatten)] + pub instant_lock: InstantLockConfig, // todo: this should probably be coming from Tenderdash config. It's a test only param /// Approximately how often are blocks produced @@ -209,7 +206,7 @@ pub struct PlatformConfig { #[serde(default)] pub rejections_path: Option, - // todo: put this in tests like #[cfg(test)] + #[cfg(feature = "testing-config")] /// This should be None, except in the case of Testing platform #[serde(skip)] pub testing_configs: PlatformTestConfig, @@ -226,6 +223,317 @@ pub struct PlatformConfig { pub tokio_console_retention_secs: u64, } +/// A config suitable for a quorum configuration +pub trait QuorumLikeConfig: Sized { + /// Quorum type + fn quorum_type(&self) -> QuorumType; + + /// Quorum size + fn quorum_size(&self) -> u16; + + /// Quorum DKG interval + fn quorum_window(&self) -> u32; + + /// Quorum active signers count + fn quorum_active_signers(&self) -> u16; + + /// Quorum rotation (dip24) or classic + fn quorum_rotation(&self) -> bool; +} + +/// Chain Lock quorum configuration +#[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)] +pub struct ValidatorSetConfig { + /// The quorum type used for verifying chain locks + #[serde( + rename = "validator_set_quorum_type", + serialize_with = "serialize_quorum_type", + deserialize_with = "deserialize_quorum_type" + )] + pub quorum_type: QuorumType, + + /// The quorum size + #[serde( + rename = "validator_set_quorum_size", + deserialize_with = "from_str_or_number" + )] + pub quorum_size: u16, + + /// The quorum window (DKG interval) + /// On Mainnet Chain Locks are signed using 400_60: One quorum in every 288 blocks and activeQuorumCount is 4. + /// On Testnet Chain Locks are signed using 50_60: One quorum in every 24 blocks and activeQuorumCount is 24. + #[serde( + rename = "validator_set_quorum_window", + deserialize_with = "from_str_or_number" + )] + pub quorum_window: u32, + + /// The number of active signers + #[serde( + rename = "validator_set_quorum_active_signers", + deserialize_with = "from_str_or_number" + )] + pub quorum_active_signers: u16, + + /// Whether the quorum is rotated DIP24 or classic + #[serde( + rename = "validator_set_quorum_rotation", + deserialize_with = "from_str_or_number" + )] + pub quorum_rotation: bool, +} + +impl Default for ValidatorSetConfig { + fn default() -> Self { + // Mainnet + Self::default_100_67() + } +} + +impl ValidatorSetConfig { + /// Creates a default config for LLMQ 100 67 + pub fn default_100_67() -> Self { + Self { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 100, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + } + } +} + +impl QuorumLikeConfig for ValidatorSetConfig { + fn quorum_type(&self) -> QuorumType { + self.quorum_type + } + + fn quorum_size(&self) -> u16 { + self.quorum_size + } + + fn quorum_window(&self) -> u32 { + self.quorum_window + } + + fn quorum_active_signers(&self) -> u16 { + self.quorum_active_signers + } + + fn quorum_rotation(&self) -> bool { + self.quorum_rotation + } +} + +/// Chain Lock quorum configuration +#[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)] +pub struct ChainLockConfig { + /// The quorum type used for verifying chain locks + #[serde( + rename = "chain_lock_quorum_type", + serialize_with = "serialize_quorum_type", + deserialize_with = "deserialize_quorum_type" + )] + pub quorum_type: QuorumType, + + /// The quorum size + #[serde( + rename = "chain_lock_quorum_size", + deserialize_with = "from_str_or_number" + )] + pub quorum_size: u16, + + /// The quorum window (DKG interval) + /// On Mainnet Chain Locks are signed using 400_60: One quorum in every 288 blocks and activeQuorumCount is 4. + /// On Testnet Chain Locks are signed using 50_60: One quorum in every 24 blocks and activeQuorumCount is 24. + #[serde( + rename = "chain_lock_quorum_window", + deserialize_with = "from_str_or_number" + )] + pub quorum_window: u32, + + /// The number of active signers + #[serde( + rename = "chain_lock_quorum_active_signers", + deserialize_with = "from_str_or_number" + )] + pub quorum_active_signers: u16, + + /// Whether the quorum is rotated DIP24 or classic + #[serde( + rename = "chain_lock_quorum_rotation", + deserialize_with = "from_str_or_number" + )] + pub quorum_rotation: bool, +} + +impl Default for ChainLockConfig { + fn default() -> Self { + // Mainnet + Self { + quorum_type: QuorumType::Llmq400_60, + quorum_size: 400, + quorum_window: 24 * 12, + quorum_active_signers: 4, + quorum_rotation: false, + } + } +} + +impl QuorumLikeConfig for ChainLockConfig { + fn quorum_type(&self) -> QuorumType { + self.quorum_type + } + + fn quorum_size(&self) -> u16 { + self.quorum_size + } + + fn quorum_window(&self) -> u32 { + self.quorum_window + } + + fn quorum_active_signers(&self) -> u16 { + self.quorum_active_signers + } + + fn quorum_rotation(&self) -> bool { + self.quorum_rotation + } +} + +impl ChainLockConfig { + /// Creates a default config for LLMQ 100 67 + pub fn default_100_67() -> Self { + Self { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 100, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + } + } +} + +/// Chain Lock quorum configuration +#[derive(Clone, Debug, Serialize, Deserialize, Encode, Decode)] +pub struct InstantLockConfig { + /// The quorum type used for verifying chain locks + #[serde( + rename = "instant_lock_quorum_type", + serialize_with = "serialize_quorum_type", + deserialize_with = "deserialize_quorum_type" + )] + pub quorum_type: QuorumType, + + /// The quorum size + #[serde( + rename = "instant_lock_quorum_size", + deserialize_with = "from_str_or_number" + )] + pub quorum_size: u16, + + /// The quorum window (DKG interval) + /// On Mainnet Chain Locks are signed using 400_60: One quorum in every 288 blocks and activeQuorumCount is 4. + /// On Testnet Chain Locks are signed using 50_60: One quorum in every 24 blocks and activeQuorumCount is 24. + #[serde( + rename = "instant_lock_quorum_window", + deserialize_with = "from_str_or_number" + )] + pub quorum_window: u32, + + /// The number of active signers + #[serde( + rename = "instant_lock_quorum_active_signers", + deserialize_with = "from_str_or_number" + )] + pub quorum_active_signers: u16, + + /// Whether the quorum is rotated DIP24 or classic + #[serde( + rename = "instant_lock_quorum_rotation", + deserialize_with = "from_str_or_number" + )] + pub quorum_rotation: bool, +} + +impl Default for InstantLockConfig { + fn default() -> Self { + // Mainnet + Self { + quorum_type: QuorumType::Llmq60_75, + quorum_active_signers: 32, + quorum_size: 60, + quorum_window: 24 * 12, + quorum_rotation: true, + } + } +} + +impl InstantLockConfig { + /// Creates a default config for LLMQ 100 67 + pub fn default_100_67() -> Self { + Self { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 100, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + } + } +} + +impl QuorumLikeConfig for InstantLockConfig { + fn quorum_type(&self) -> QuorumType { + self.quorum_type + } + + fn quorum_size(&self) -> u16 { + self.quorum_size + } + + fn quorum_window(&self) -> u32 { + self.quorum_window + } + + fn quorum_active_signers(&self) -> u16 { + self.quorum_active_signers + } + + fn quorum_rotation(&self) -> bool { + self.quorum_rotation + } +} + +fn serialize_quorum_type(quorum_type: &QuorumType, serializer: S) -> Result +where + S: serde::Serializer, +{ + serializer.serialize_str(quorum_type.to_string().as_str()) +} + +fn deserialize_quorum_type<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + let quorum_type_name = String::deserialize(deserializer)?; + + let quorum_type = if let Ok(t) = quorum_type_name.trim().parse::() { + QuorumType::from(t) + } else { + QuorumType::from(quorum_type_name.as_str()) + }; + + if quorum_type == QuorumType::UNKNOWN { + return Err(serde::de::Error::custom(format!( + "unsupported QUORUM_TYPE: {}", + quorum_type_name + ))); + }; + + Ok(quorum_type) +} + impl ExecutionConfig { fn default_verify_sum_trees() -> bool { true @@ -256,43 +564,8 @@ impl PlatformConfig { fn default_tokio_console_retention_secs() -> u64 { 60 * 3 } - - /// Return type of quorum - pub fn validator_set_quorum_type(&self) -> QuorumType { - let found = if let Ok(t) = self.validator_set_quorum_type.trim().parse::() { - QuorumType::from(t) - } else { - QuorumType::from(self.validator_set_quorum_type.as_str()) - }; - - if found == QuorumType::UNKNOWN { - panic!( - "config: unsupported QUORUM_TYPE: {}", - self.validator_set_quorum_type - ); - } - - found - } - - /// Return type of quorum for validating chain locks - pub fn chain_lock_quorum_type(&self) -> QuorumType { - let found = if let Ok(t) = self.chain_lock_quorum_type.trim().parse::() { - QuorumType::from(t) - } else { - QuorumType::from(self.chain_lock_quorum_type.as_str()) - }; - - if found == QuorumType::UNKNOWN { - panic!( - "config: unsupported QUORUM_TYPE: {}", - self.chain_lock_quorum_type - ); - } - - found - } } + /// create new object using values from environment variables pub trait FromEnv { /// create new object using values from environment variables @@ -338,11 +611,27 @@ impl Default for PlatformConfig { impl PlatformConfig { pub fn default_local() -> Self { Self { - validator_set_quorum_type: "llmq_test_platform".to_string(), - chain_lock_quorum_type: "llmq_test".to_string(), - validator_set_quorum_size: 3, - chain_lock_quorum_size: 3, - chain_lock_quorum_window: 24, + validator_set: ValidatorSetConfig { + quorum_type: QuorumType::LlmqTestPlatform, + quorum_size: 3, + quorum_window: 24, + quorum_active_signers: 2, + quorum_rotation: false, + }, + chain_lock: ChainLockConfig { + quorum_type: QuorumType::LlmqTest, + quorum_active_signers: 2, + quorum_size: 3, + quorum_window: 24, + quorum_rotation: false, + }, + instant_lock: InstantLockConfig { + quorum_type: QuorumType::LlmqTest, + quorum_active_signers: 2, + quorum_size: 3, + quorum_window: 24, + quorum_rotation: false, + }, block_spacing_ms: 5000, drive: Default::default(), abci: Default::default(), @@ -350,6 +639,7 @@ impl PlatformConfig { execution: Default::default(), db_path: PathBuf::from("/var/lib/dash-platform/data"), rejections_path: Some(PathBuf::from("/var/log/dash/rejected")), + #[cfg(feature = "testing-config")] testing_configs: PlatformTestConfig::default(), tokio_console_enabled: false, tokio_console_address: PlatformConfig::default_tokio_console_address(), @@ -362,11 +652,27 @@ impl PlatformConfig { pub fn default_testnet() -> Self { Self { - validator_set_quorum_type: "llmq_25_67".to_string(), - chain_lock_quorum_type: "llmq_50_60".to_string(), - validator_set_quorum_size: 25, - chain_lock_quorum_size: 50, - chain_lock_quorum_window: 24, + validator_set: ValidatorSetConfig { + quorum_type: QuorumType::Llmq25_67, + quorum_size: 25, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, + chain_lock: ChainLockConfig { + quorum_type: QuorumType::Llmq50_60, + quorum_active_signers: 24, + quorum_size: 50, + quorum_window: 24, + quorum_rotation: false, + }, + instant_lock: InstantLockConfig { + quorum_type: QuorumType::Llmq60_75, + quorum_active_signers: 32, + quorum_size: 60, + quorum_window: 24 * 12, + quorum_rotation: true, + }, block_spacing_ms: 5000, drive: Default::default(), abci: Default::default(), @@ -374,6 +680,7 @@ impl PlatformConfig { execution: Default::default(), db_path: PathBuf::from("/var/lib/dash-platform/data"), rejections_path: Some(PathBuf::from("/var/log/dash/rejected")), + #[cfg(feature = "testing-config")] testing_configs: PlatformTestConfig::default(), initial_protocol_version: Self::default_initial_protocol_version(), prometheus_bind_address: None, @@ -386,11 +693,27 @@ impl PlatformConfig { pub fn default_mainnet() -> Self { Self { - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_400_60".to_string(), - validator_set_quorum_size: 100, - chain_lock_quorum_size: 400, - chain_lock_quorum_window: 288, + validator_set: ValidatorSetConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 100, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, + chain_lock: ChainLockConfig { + quorum_type: QuorumType::Llmq400_60, + quorum_active_signers: 4, + quorum_size: 400, + quorum_window: 24 * 12, + quorum_rotation: false, + }, + instant_lock: InstantLockConfig { + quorum_type: QuorumType::Llmq60_75, + quorum_active_signers: 32, + quorum_size: 60, + quorum_window: 24 * 12, + quorum_rotation: true, + }, block_spacing_ms: 5000, drive: Default::default(), abci: Default::default(), @@ -398,6 +721,7 @@ impl PlatformConfig { execution: Default::default(), db_path: PathBuf::from("/var/lib/dash-platform/data"), rejections_path: Some(PathBuf::from("/var/log/dash/rejected")), + #[cfg(feature = "testing-config")] testing_configs: PlatformTestConfig::default(), initial_protocol_version: Self::default_initial_protocol_version(), prometheus_bind_address: None, @@ -409,30 +733,37 @@ impl PlatformConfig { } } +#[cfg(feature = "testing-config")] /// Configs that should only happen during testing -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug)] pub struct PlatformTestConfig { /// Block signing pub block_signing: bool, /// Block signature verification pub block_commit_signature_verification: bool, + /// Disable instant lock signature verification + pub disable_instant_lock_signature_verification: bool, } +#[cfg(feature = "testing-config")] impl PlatformTestConfig { /// Much faster config for tests pub fn default_with_no_block_signing() -> Self { Self { block_signing: false, block_commit_signature_verification: false, + disable_instant_lock_signature_verification: false, } } } +#[cfg(feature = "testing-config")] impl Default for PlatformTestConfig { fn default() -> Self { Self { block_signing: true, block_commit_signature_verification: true, + disable_instant_lock_signature_verification: false, } } } @@ -468,7 +799,7 @@ mod tests { let config = super::PlatformConfig::from_env().expect("expected config from env"); assert!(config.execution.verify_sum_trees); - assert_ne!(config.validator_set_quorum_type(), QuorumType::UNKNOWN); + assert_ne!(config.validator_set.quorum_type, QuorumType::UNKNOWN); for id in vectors { matches!(config.abci.log[id.0].destination, LogDestination::Bytes); } diff --git a/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs b/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs index e6fa1e13e84..155cced9dad 100644 --- a/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/check_tx/v0/mod.rs @@ -205,7 +205,7 @@ where #[cfg(test)] mod tests { - use crate::config::PlatformConfig; + use crate::config::{PlatformConfig, PlatformTestConfig}; use crate::platform_types::event_execution_result::EventExecutionResult::{ SuccessfulPaidExecution, UnpaidConsensusExecutionError, UnsuccessfulPaidExecution, }; @@ -276,14 +276,17 @@ mod tests { #[test] #[ignore] fn verify_check_tx_on_data_contract_create() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let protocol_version = platform_state.current_protocol_version_in_consensus(); @@ -370,14 +373,17 @@ mod tests { #[test] fn data_contract_create_check_tx() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let protocol_version = platform_state.current_protocol_version_in_consensus(); @@ -501,14 +507,17 @@ mod tests { #[test] fn data_contract_create_check_tx_for_invalid_contract() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let protocol_version = platform_state.current_protocol_version_in_consensus(); @@ -693,14 +702,17 @@ mod tests { #[test] fn data_contract_create_check_tx_priority() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let protocol_version = platform_state.current_protocol_version_in_consensus(); @@ -838,14 +850,17 @@ mod tests { #[test] fn data_contract_create_check_tx_after_identity_balance_used_up() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let protocol_version = platform_state.current_protocol_version_in_consensus(); @@ -962,14 +977,17 @@ mod tests { #[test] fn data_contract_update_check_tx() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let protocol_version = platform_state.current_protocol_version_in_consensus(); @@ -1158,14 +1176,17 @@ mod tests { #[test] fn data_contract_update_check_tx_for_invalid_update() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let protocol_version = platform_state.current_protocol_version_in_consensus(); @@ -1389,16 +1410,19 @@ mod tests { #[test] fn document_update_check_tx() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) .build_with_mock_rpc() .set_genesis_state(); - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); - let platform_state = platform.state.load(); let platform_version = platform_state.current_platform_version().unwrap(); @@ -1577,14 +1601,17 @@ mod tests { #[test] fn identity_top_up_check_tx() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let platform_version = platform_state.current_platform_version().unwrap(); @@ -1716,14 +1743,17 @@ mod tests { #[test] fn identity_cant_double_top_up() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let platform_version = platform_state.current_platform_version().unwrap(); @@ -1887,14 +1917,17 @@ mod tests { #[test] fn identity_top_up_with_unknown_identity_doesnt_panic() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let platform_version = platform_state.current_platform_version().unwrap(); @@ -1981,14 +2014,17 @@ mod tests { #[test] fn identity_cant_create_with_used_outpoint() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let platform_version = platform_state.current_platform_version().unwrap(); @@ -2199,14 +2235,17 @@ mod tests { #[test] fn identity_can_create_with_semi_used_outpoint() { - let mut platform = TestPlatformBuilder::new() - .with_config(PlatformConfig::default()) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let platform_version = platform_state.current_platform_version().unwrap(); @@ -2513,14 +2552,17 @@ mod tests { config.abci.keys.dpns_second_public_key = high_public_key.serialize().to_vec(); - let mut platform = TestPlatformBuilder::new() - .with_config(config) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let platform_version = platform_state.current_platform_version().unwrap(); @@ -2627,14 +2669,17 @@ mod tests { config.abci.keys.dashpay_second_public_key = high_public_key.serialize().to_vec(); - let mut platform = TestPlatformBuilder::new() - .with_config(config) - .build_with_mock_rpc(); + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); + let platform = TestPlatformBuilder::new() + .with_config(platform_config) + .build_with_mock_rpc(); let platform_state = platform.state.load(); let platform_version = platform_state.current_platform_version().unwrap(); diff --git a/packages/rs-drive-abci/src/execution/engine/finalize_block_proposal/v0/mod.rs b/packages/rs-drive-abci/src/execution/engine/finalize_block_proposal/v0/mod.rs index ae78f603616..68b226873b1 100644 --- a/packages/rs-drive-abci/src/execution/engine/finalize_block_proposal/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/engine/finalize_block_proposal/v0/mod.rs @@ -154,18 +154,23 @@ where return Ok(validation_result.into()); } + // Verify commit + // In production this will always be true - if self + #[cfg(not(feature = "testing-config"))] + let verify_commit_signature = true; + + #[cfg(feature = "testing-config")] + let verify_commit_signature = self .config .testing_configs - .block_commit_signature_verification - { - // Verify commit + .block_commit_signature_verification; + if verify_commit_signature { let quorum_public_key = last_committed_state .current_validator_set()? .threshold_public_key(); - let quorum_type = self.config.validator_set_quorum_type(); + let quorum_type = self.config.validator_set.quorum_type; // TODO: We already had commit in the function above, why do we need to create it again with clone? let commit = Commit::new_from_cleaned( commit_info.clone(), diff --git a/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/v0/mod.rs b/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/v0/mod.rs index 29fba3c5148..75bd88a55cf 100644 --- a/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/engine/initialization/init_chain/v0/mod.rs @@ -52,7 +52,8 @@ where let mut initial_platform_state = PlatformState::default_with_protocol_versions( request.initial_protocol_version, request.initial_protocol_version, - ); + &self.config, + )?; let genesis_block_info = BlockInfo { height: request.initial_height, diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/add_process_epoch_change_operations/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/add_process_epoch_change_operations/v0/mod.rs index e705b047ba0..3e34b5c5822 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/add_process_epoch_change_operations/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/add_process_epoch_change_operations/v0/mod.rs @@ -252,7 +252,9 @@ mod tests { let block_platform_state = PlatformState::default_with_protocol_versions( INITIAL_PROTOCOL_VERSION, INITIAL_PROTOCOL_VERSION, - ); + &platform.config, + ) + .expect("failed to create platform state"); let block_execution_context = BlockExecutionContextV0 { block_state_info: block_info.clone().into(), diff --git a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/process_block_fees/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/process_block_fees/v0/mod.rs index 0b92b87f241..d6df6c83012 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/process_block_fees/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/block_fee_processing/process_block_fees/v0/mod.rs @@ -283,7 +283,9 @@ mod tests { let block_platform_state = PlatformState::default_with_protocol_versions( INITIAL_PROTOCOL_VERSION, INITIAL_PROTOCOL_VERSION, - ); + &platform.config, + ) + .expect("failed to create default platform state"); let block_execution_context = BlockExecutionContextV0 { block_state_info: block_info.clone().into(), diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs index 50ad933c426..55c4b053321 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_quorum_info/v0/mod.rs @@ -3,17 +3,45 @@ use crate::error::Error; use crate::platform_types::platform::Platform; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use crate::platform_types::platform_state::PlatformState; -use crate::platform_types::signature_verification_quorums::SignatureVerificationQuorumsV0Methods; +use dashcore_rpc::json::{ExtendedQuorumListResult, QuorumType}; use std::collections::BTreeMap; +use std::fmt::Display; use crate::platform_types::validator_set::v0::{ValidatorSetV0, ValidatorSetV0Getters}; use crate::platform_types::validator_set::ValidatorSet; use crate::rpc::core::CoreRPCLike; +use crate::platform_types::signature_verification_quorum_set::{ + SignatureVerificationQuorumSet, SignatureVerificationQuorumSetV0Methods, VerificationQuorum, +}; use dpp::bls_signatures::PublicKey as BlsPublicKey; use dpp::dashcore::QuorumHash; use tracing::Level; +#[derive(Copy, Clone)] +enum QuorumSetType { + ChainLock(QuorumType), + InstantLock(QuorumType), +} + +impl QuorumSetType { + fn quorum_type(&self) -> QuorumType { + match self { + QuorumSetType::ChainLock(quorum_type) => *quorum_type, + QuorumSetType::InstantLock(quorum_type) => *quorum_type, + } + } +} + +impl Display for QuorumSetType { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + QuorumSetType::ChainLock(quorum_type) => write!(f, "chain lock ({quorum_type})"), + QuorumSetType::InstantLock(quorum_type) => write!(f, "instant lock ({quorum_type})"), + } + } +} + impl Platform where C: CoreRPCLike, @@ -63,8 +91,9 @@ where .core_rpc .get_quorum_listextended(Some(core_block_height))?; - let validator_set_quorum_type = self.config.validator_set_quorum_type(); - let chain_lock_quorum_type = self.config.chain_lock_quorum_type(); + let validator_set_quorum_type = self.config.validator_set.quorum_type; + let chain_lock_quorum_type = self.config.chain_lock.quorum_type; + let instant_lock_quorum_type = self.config.instant_lock.quorum_type; let validator_quorums_list: BTreeMap<_, _> = extended_quorum_list .quorums_by_type @@ -72,7 +101,7 @@ where .ok_or(Error::Execution(ExecutionError::DashCoreBadResponseError( format!( "expected quorums of type {}, but did not receive any from Dash Core", - self.config.validator_set_quorum_type + self.config.validator_set.quorum_type ), )))? .into_iter() @@ -90,10 +119,10 @@ where if !retain { tracing::trace!( ?quorum_hash, - quorum_type = ?self.config.validator_set_quorum_type(), + quorum_type = ?self.config.validator_set.quorum_type, "removed validator set {} with quorum type {}", quorum_hash, - self.config.validator_set_quorum_type() + self.config.validator_set.quorum_type ) } @@ -102,7 +131,7 @@ where // Fetch quorum info and their keys from the RPC for new quorums let mut quorum_infos = validator_quorums_list - .iter() + .into_iter() .filter(|(key, _)| { !block_platform_state .validator_sets() @@ -110,12 +139,12 @@ where }) .map(|(key, _)| { let quorum_info_result = self.core_rpc.get_quorum_info( - self.config.validator_set_quorum_type(), - key, + self.config.validator_set.quorum_type, + &key, None, )?; - Ok((*key, quorum_info_result)) + Ok((key, quorum_info_result)) }) .collect::, Error>>()?; @@ -141,17 +170,17 @@ where tracing::trace!( ?validator_set, ?quorum_hash, - quorum_type = ?self.config.validator_set_quorum_type(), + quorum_type = ?self.config.validator_set.quorum_type, "add new validator set {} with quorum type {}", quorum_hash, - self.config.validator_set_quorum_type() + self.config.validator_set.quorum_type ); Ok((quorum_hash, validator_set)) }) .collect::, Error>>()?; - let added_a_validator_set = !new_validator_sets.is_empty(); + let is_validator_set_updated = !new_validator_sets.is_empty() || removed_a_validator_set; // Add new validator_sets entries block_platform_state @@ -173,139 +202,227 @@ where } }); - if validator_set_quorum_type == chain_lock_quorum_type { - // Remove validator_sets entries that are no longer valid for the core block height - if removed_a_validator_set || added_a_validator_set { - let quorums = block_platform_state - .validator_sets() - .iter() - .map(|(quorum_hash, validator_set)| { - (*quorum_hash, validator_set.threshold_public_key().clone()) - }) - .collect(); - - tracing::trace!("updated chain lock validating quorums to current validator set"); - - if platform_state.is_some() { - // we already have state, so we update last and previous quorums - block_platform_state - .chain_lock_validating_quorums_mut() - .rotate_quorums(quorums, last_committed_core_height, core_block_height); - } else { - // the only case where there will be no platform_state is init chain, - // so there is no previous quorums to update - block_platform_state - .chain_lock_validating_quorums_mut() - .set_current_quorums(quorums) - } + // Update Chain Lock quorums + + // Use already updated validator sets if we use the same quorums + let quorum_set_type = QuorumSetType::ChainLock(chain_lock_quorum_type); + let are_chainlock_quorum_updated = if chain_lock_quorum_type == validator_set_quorum_type { + // Update only in case if there are any changes + if is_validator_set_updated { + Self::update_quorums_from_validator_set( + quorum_set_type, + platform_state, + block_platform_state, + core_block_height, + ); } + + is_validator_set_updated } else { - let chain_lock_quorums_list: BTreeMap<_, _> = extended_quorum_list - .quorums_by_type - .remove(&chain_lock_quorum_type) - .ok_or(Error::Execution(ExecutionError::DashCoreBadResponseError( - format!( - "expected quorums of type {}, but did not receive any from Dash Core", - self.config.chain_lock_quorum_type - ), - )))? - .into_iter() - .map(|(quorum_hash, extended_quorum_details)| { - (quorum_hash, extended_quorum_details.quorum_index) - }) - .collect(); - - let mut removed_a_chain_lock_validating_quorum = false; - - // Remove chain_lock_validating_quorums entries that are no longer valid for the core block height - block_platform_state - .chain_lock_validating_quorums_mut() - .current_quorums_mut() - .retain(|quorum_hash, _| { - let retain = chain_lock_quorums_list.contains_key::(quorum_hash); - if !retain { - tracing::trace!( - ?quorum_hash, - quorum_type = ?chain_lock_quorum_type, - "removed old chain lock quorum {} with quorum type {}", - quorum_hash, - chain_lock_quorum_type - ); - } - removed_a_chain_lock_validating_quorum |= !retain; - retain - }); - - // Fetch quorum info and their keys from the RPC for new quorums - let quorum_infos = chain_lock_quorums_list - .iter() - .filter(|(key, _)| { - !block_platform_state - .chain_lock_validating_quorums() - .current_quorums() - .contains_key::(key) - }) - .map(|(key, _)| { - let quorum_info_result = - self.core_rpc - .get_quorum_info(chain_lock_quorum_type, key, None)?; - - Ok((*key, quorum_info_result)) - }) - .collect::, Error>>()?; - - let added_a_chain_lock_validating_quorum = !quorum_infos.is_empty(); - - if added_a_chain_lock_validating_quorum { - // Map to chain lock validating quorums - let new_chain_lock_quorums = quorum_infos - .into_iter() - .map(|(quorum_hash, info_result)| { - let public_key = match BlsPublicKey::from_bytes( - info_result.quorum_public_key.as_slice(), - ) - .map_err(ExecutionError::BlsErrorFromDashCoreResponse) - { - Ok(public_key) => public_key, - Err(e) => return Err(e.into()), - }; - - tracing::trace!( - ?public_key, - ?quorum_hash, - quorum_type = ?chain_lock_quorum_type, - "add new chain lock quorum {} with quorum type {}", - quorum_hash, - chain_lock_quorum_type - ); - - Ok((quorum_hash, public_key)) - }) - .collect::, Error>>()?; - - // Add new validator_sets entries - block_platform_state - .chain_lock_validating_quorums_mut() - .current_quorums_mut() - .extend(new_chain_lock_quorums); + self.update_quorums_from_quorum_list( + quorum_set_type, + block_platform_state.chain_lock_validating_quorums_mut(), + platform_state, + &extended_quorum_list, + last_committed_core_height, + core_block_height, + )? + }; + + // Update Instant Lock quorums + + // Use already updated chainlock quorums if we use the same quorum type + let quorum_set_type = QuorumSetType::InstantLock(instant_lock_quorum_type); + if instant_lock_quorum_type == chain_lock_quorum_type { + if are_chainlock_quorum_updated { + tracing::trace!( + "updated instant lock validating quorums to chain lock validating quorums", + ); + + block_platform_state.set_instant_lock_validating_quorums( + block_platform_state.chain_lock_validating_quorums().clone(), + ); + } + // The same for validator set quorum type + } else if instant_lock_quorum_type == validator_set_quorum_type { + if is_validator_set_updated { + Self::update_quorums_from_validator_set( + quorum_set_type, + platform_state, + block_platform_state, + core_block_height, + ); } + } else { + self.update_quorums_from_quorum_list( + quorum_set_type, + block_platform_state.instant_lock_validating_quorums_mut(), + platform_state, + &extended_quorum_list, + last_committed_core_height, + core_block_height, + )?; + } + + Ok(()) + } - if added_a_chain_lock_validating_quorum || removed_a_chain_lock_validating_quorum { - if let Some(old_state) = platform_state { - let previous_chain_lock_validating_quorums = - old_state.chain_lock_validating_quorums().current_quorums(); - - block_platform_state - .chain_lock_validating_quorums_mut() - .set_previous_past_quorums( - previous_chain_lock_validating_quorums.clone(), - last_committed_core_height, - core_block_height, - ); + fn update_quorums_from_validator_set( + quorum_set_type: QuorumSetType, + platform_state: Option<&PlatformState>, + block_platform_state: &mut PlatformState, + core_block_height: u32, + ) { + let quorums = block_platform_state + .validator_sets() + .iter() + .map(|(quorum_hash, validator_set)| { + ( + *quorum_hash, + VerificationQuorum { + public_key: validator_set.threshold_public_key().clone(), + index: validator_set.quorum_index(), + }, + ) + }) + .collect(); + + tracing::trace!( + "updated {} validating quorums to current validator set", + quorum_set_type + ); + + let last_committed_core_height = block_platform_state.last_committed_core_height(); + + let quorum_set = quorum_set_by_type_mut(block_platform_state, &quorum_set_type); + + if platform_state.is_some() { + // we already have state, so we update last and previous quorums + quorum_set.replace_quorums(quorums, last_committed_core_height, core_block_height); + } else { + // the only case where there will be no platform_state is init chain, + // so there is no previous quorums to update + quorum_set.set_current_quorums(quorums) + } + } + + fn update_quorums_from_quorum_list( + &self, + quorum_set_type: QuorumSetType, + quorum_set: &mut SignatureVerificationQuorumSet, + platform_state: Option<&PlatformState>, + full_quorum_list: &ExtendedQuorumListResult, + last_committed_core_height: u32, + next_core_height: u32, + ) -> Result { + let quorums_list: BTreeMap<_, _> = full_quorum_list + .quorums_by_type + .get(&quorum_set_type.quorum_type()) + .ok_or(Error::Execution(ExecutionError::DashCoreBadResponseError( + format!( + "expected quorums {}, but did not receive any from Dash Core", + quorum_set_type + ), + )))? + .iter() + .map(|(quorum_hash, extended_quorum_details)| { + (quorum_hash, extended_quorum_details.quorum_index) + }) + .collect(); + + let mut removed_a_validating_quorum = false; + + // Remove validating_quorums entries that are no longer valid for the core block height + // and update quorum index for existing validator sets + quorum_set + .current_quorums_mut() + .retain(|quorum_hash, quorum| { + let retain = match quorums_list.get(quorum_hash) { + Some(index) => { + quorum.index = *index; + true + } + None => false, + }; + + if !retain { + tracing::trace!( + ?quorum_hash, + quorum_type = ?quorum_set_type.quorum_type(), + "removed old {} quorum {}", + quorum_set_type, + quorum_hash, + ); } + removed_a_validating_quorum |= !retain; + retain + }); + + // Fetch quorum info and their keys from the RPC for new quorums + // and then create VerificationQuorum instances + let new_quorums = quorums_list + .into_iter() + .filter(|(quorum_hash, _)| { + !quorum_set + .current_quorums() + .contains_key::(quorum_hash) + }) + .map(|(quorum_hash, index)| { + let quorum_info = self.core_rpc.get_quorum_info( + quorum_set_type.quorum_type(), + quorum_hash, + None, + )?; + + let public_key = + match BlsPublicKey::from_bytes(quorum_info.quorum_public_key.as_slice()) + .map_err(ExecutionError::BlsErrorFromDashCoreResponse) + { + Ok(public_key) => public_key, + Err(e) => return Err(e.into()), + }; + + tracing::trace!( + ?public_key, + ?quorum_hash, + index, + quorum_type = ?quorum_set_type.quorum_type(), + "add new {} quorum {}", + quorum_set_type, + quorum_hash, + ); + + Ok((*quorum_hash, VerificationQuorum { public_key, index })) + }) + .collect::, Error>>()?; + + let are_quorums_updated = !new_quorums.is_empty() || removed_a_validating_quorum; + + quorum_set.current_quorums_mut().extend(new_quorums); + + if are_quorums_updated { + if let Some(old_state) = platform_state { + let previous_validating_quorums = + old_state.chain_lock_validating_quorums().current_quorums(); + + quorum_set.set_previous_past_quorums( + previous_validating_quorums.clone(), + last_committed_core_height, + next_core_height, + ); } } - Ok(()) + Ok(are_quorums_updated) + } +} + +fn quorum_set_by_type_mut<'p>( + block_platform_state: &'p mut PlatformState, + quorum_set_type: &QuorumSetType, +) -> &'p mut SignatureVerificationQuorumSet { + match quorum_set_type { + QuorumSetType::ChainLock(_) => block_platform_state.chain_lock_validating_quorums_mut(), + QuorumSetType::InstantLock(_) => block_platform_state.instant_lock_validating_quorums_mut(), } } diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/mod.rs index 11d1b02f782..3af3b3fbd2d 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/choose_quorum/mod.rs @@ -21,7 +21,7 @@ where C: CoreRPCLike, { /// Based on DIP8 deterministically chooses a pseudorandom quorum from the list of quorums - /// + // TODO: use CoreQuorumSet.select_quorums instead pub fn choose_quorum<'a>( llmq_quorum_type: QuorumType, quorums: &'a BTreeMap, diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/make_sure_core_is_synced_to_chain_lock/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/make_sure_core_is_synced_to_chain_lock/v0/mod.rs index 4ca9f9705cb..f92183277b4 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/make_sure_core_is_synced_to_chain_lock/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/make_sure_core_is_synced_to_chain_lock/v0/mod.rs @@ -18,6 +18,8 @@ where ) -> Result { let given_chain_lock_height = chain_lock.block_height; // We need to make sure core is synced to the core height we see as valid for the state transitions + + // TODO: submit_chain_lock responds with invalid signature. We should handle it properly and return CoreSyncStatus let best_chain_locked_height = self.core_rpc.submit_chain_lock(chain_lock)?; Ok(if best_chain_locked_height >= given_chain_lock_height { CoreSyncStatus::Done diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs index d0f7b60af84..a48fc30c670 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/core_chain_lock/verify_chain_lock_locally/v0/mod.rs @@ -12,7 +12,7 @@ use crate::rpc::core::CoreRPCLike; use crate::error::execution::ExecutionError; use crate::platform_types::platform_state::v0::PlatformStateV0Methods; use crate::platform_types::platform_state::PlatformState; -use crate::platform_types::signature_verification_quorums::SignatureVerificationQuorumsV0Methods; +use crate::platform_types::signature_verification_quorum_set::SignatureVerificationQuorumSetV0Methods; use dpp::version::PlatformVersion; const CHAIN_LOCK_REQUEST_ID_PREFIX: &str = "clsig"; @@ -31,15 +31,20 @@ where round: u32, platform_state: &PlatformState, chain_lock: &ChainLock, - platform_version: &PlatformVersion, + _platform_version: &PlatformVersion, ) -> Result, Error> { + let quorum_set = platform_state.chain_lock_validating_quorums(); + let quorum_config = quorum_set.config(); + // First verify that the signature conforms to a signature - let signature = G2Element::from_bytes(chain_lock.signature.as_bytes())?; + let Ok(signature) = G2Element::from_bytes(chain_lock.signature.as_bytes()) else { + return Ok(Some(false)); + }; // we attempt to verify the chain lock locally let chain_lock_height = chain_lock.block_height; - let window_width = self.config.chain_lock_quorum_window; + let window_width = quorum_config.window; // The last block in the window where the quorums would be the same let last_block_in_window = platform_state.last_committed_core_height() @@ -63,10 +68,12 @@ where return Ok(None); // the chain lock is too far in the future or the past to verify locally } - let mut selected_quorum_sets = platform_state + let mut selected_quorums = platform_state .chain_lock_validating_quorums() .select_quorums(chain_lock_height, verification_height); + // TODO: We can use chain_lock.request_id() + // From DIP 8: https://github.com/dashpay/dips/blob/master/dip-0008.md#finalization-of-signed-blocks // The request id is SHA256("clsig", blockHeight) and the message hash is the block hash of the previously successful attempt. @@ -86,20 +93,15 @@ where ); // Based on the deterministic masternode list at the given height, a quorum must be selected that was active at the time this block was mined - let probable_quorums = selected_quorum_sets.next().ok_or_else(|| { + + let probable_quorums = selected_quorums.next().ok_or_else(|| { Error::Execution(ExecutionError::CorruptedCodeExecution( - "at lest one set of quorums must be selected", + "No quorums selected for chain lock signature verification for specified height", )) })?; - let quorum = Platform::::choose_quorum( - self.config.chain_lock_quorum_type(), - probable_quorums, - request_id.as_ref(), - platform_version, - )?; - - let Some((quorum_hash, public_key)) = quorum else { + let Some((quorum_hash, quorum)) = probable_quorums.choose_quorum(request_id.as_ref()) + else { return Ok(None); }; @@ -107,14 +109,19 @@ where let mut engine = sha256d::Hash::engine(); - engine.input(&[self.config.chain_lock_quorum_type() as u8]); - engine.input(quorum_hash.as_slice()); + let mut reversed_quorum_hash = quorum_hash.to_byte_array().to_vec(); + reversed_quorum_hash.reverse(); + + engine.input(&[quorum_config.quorum_type as u8]); + engine.input(reversed_quorum_hash.as_slice()); engine.input(request_id.as_byte_array()); engine.input(chain_lock.block_hash.as_byte_array()); let message_digest = sha256d::Hash::from_engine(engine); - let mut chain_lock_verified = public_key.verify(&signature, message_digest.as_ref()); + let mut chain_lock_verified = quorum + .public_key + .verify(&signature, message_digest.as_ref()); tracing::debug!( ?chain_lock, @@ -123,7 +130,7 @@ where round, chain_lock.block_height, hex::encode(message_digest.as_byte_array()), - hex::encode(quorum_hash.as_slice()), + hex::encode(reversed_quorum_hash.as_slice()), hex::encode(chain_lock.block_hash.as_byte_array()), if chain_lock_verified { "verified"} else {"not verified"}, platform_state.last_committed_core_height(), @@ -133,15 +140,10 @@ where if !chain_lock_verified { // We should also check the other quorum, as there could be the situation where the core height wasn't updated every block. - if let Some(second_to_check_quorums) = selected_quorum_sets.next() { - let quorum = Platform::::choose_quorum( - self.config.chain_lock_quorum_type(), - second_to_check_quorums, - request_id.as_ref(), - platform_version, - )?; - - let Some((quorum_hash, public_key)) = quorum else { + if let Some(second_to_check_quorums) = selected_quorums.next() { + let Some((quorum_hash, quorum)) = + second_to_check_quorums.choose_quorum(request_id.as_ref()) + else { // we return that we are not able to verify return Ok(None); }; @@ -150,14 +152,19 @@ where let mut engine = sha256d::Hash::engine(); - engine.input(&[self.config.chain_lock_quorum_type() as u8]); - engine.input(quorum_hash.as_slice()); + let mut reversed_quorum_hash = quorum_hash.to_byte_array().to_vec(); + reversed_quorum_hash.reverse(); + + engine.input(&[quorum_config.quorum_type as u8]); + engine.input(reversed_quorum_hash.as_slice()); engine.input(request_id.as_byte_array()); engine.input(chain_lock.block_hash.as_byte_array()); let message_digest = sha256d::Hash::from_engine(engine); - chain_lock_verified = public_key.verify(&signature, message_digest.as_ref()); + chain_lock_verified = quorum + .public_key + .verify(&signature, message_digest.as_ref()); tracing::debug!( ?chain_lock, @@ -166,7 +173,7 @@ where round, chain_lock.block_height, hex::encode(message_digest.as_byte_array()), - hex::encode(quorum_hash.as_slice()), + hex::encode(reversed_quorum_hash.as_slice()), hex::encode(chain_lock.block_hash.as_byte_array()), if chain_lock_verified { "verified"} else {"not verified"} ); @@ -175,17 +182,16 @@ where "chain lock was invalid for both recent and old chain lock quorums" ); } - } else if platform_state + } else if !platform_state .chain_lock_validating_quorums() - .previous_past_quorums() - .is_none() + .has_previous_past_quorums() { // we don't have old quorums, this means our node is very new. tracing::debug!( "we had no previous quorums locally, we should validate through core", ); return Ok(None); - } else if !selected_quorum_sets.should_be_verifiable { + } else if !selected_quorums.should_be_verifiable() { tracing::debug!( "we were in a situation where it would be possible we didn't have all quorums and we couldn't verify locally, we should validate through core", ); diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/mod.rs new file mode 100644 index 00000000000..87db2f8862d --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/mod.rs @@ -0,0 +1,2 @@ +/// Instant Lock recent signature verification +pub mod verify_recent_signature_locally; diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/mod.rs new file mode 100644 index 00000000000..e804ad228ef --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/mod.rs @@ -0,0 +1,47 @@ +mod v0; + +use crate::error::execution::ExecutionError; +use crate::error::Error; +use dpp::dashcore::InstantLock; + +use crate::platform_types::platform_state::PlatformState; +use dpp::version::PlatformVersion; + +/// Traits implements a method for signature verification using platform execution state +pub trait VerifyInstantLockSignature { + fn verify_recent_signature_locally( + &self, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result; +} + +impl VerifyInstantLockSignature for InstantLock { + /// Verify instant lock signature with limited quorum set what we store in Platform state + /// + /// This is a limited verification and will work properly only for recently signed instant locks. + /// Even valid instant locks that was signed some time ago will be considered invalid due to limited + /// quorum information in the platform state. In turn, this verification doesn't use Core RPC or any other + /// IO. This is done to prevent DoS attacks on slow verify instant lock signature Core RPC method. + /// In case of failed signature verification (or any knowing the fact that signing quorum is old), + /// we expect clients to use ChainAssetLockProof. + fn verify_recent_signature_locally( + &self, + platform_state: &PlatformState, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .methods + .core_instant_send_lock + .verify_recent_signature_locally + { + 0 => v0::verify_recent_instant_lock_signature_locally_v0(self, platform_state), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "InstantLock.verify_recent_signature_locally".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/v0/mod.rs new file mode 100644 index 00000000000..b7fb76a10c0 --- /dev/null +++ b/packages/rs-drive-abci/src/execution/platform_events/core_instant_send_lock/verify_recent_signature_locally/v0/mod.rs @@ -0,0 +1,144 @@ +use dpp::bls_signatures::G2Element; +use std::fmt::{Debug, Formatter}; + +use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; +use dpp::dashcore::InstantLock; + +use crate::error::execution::ExecutionError; +use crate::error::Error; + +use crate::error::serialization::SerializationError; +use crate::platform_types::platform_state::v0::PlatformStateV0Methods; +use crate::platform_types::platform_state::PlatformState; +use crate::platform_types::signature_verification_quorum_set::{ + SignatureVerificationQuorumSetV0Methods, SIGN_OFFSET, +}; + +#[inline(always)] +pub(super) fn verify_recent_instant_lock_signature_locally_v0( + instant_lock: &InstantLock, + platform_state: &PlatformState, +) -> Result { + // First verify that the signature conforms to a signature + let signature = match G2Element::from_bytes(instant_lock.signature.as_bytes()) { + Ok(signature) => signature, + Err(e) => { + tracing::trace!( + instant_lock = ?InstantLockDebug(instant_lock), + "Invalid instant Lock {} signature format: {}", + instant_lock.txid, + e, + ); + + return Ok(false); + } + }; + + let signing_height = platform_state.last_committed_core_height(); + let verification_height = signing_height.saturating_sub(SIGN_OFFSET); + + let quorum_set = platform_state.instant_lock_validating_quorums(); + + // Based on the deterministic masternode list at the given height, a quorum must be selected + // that was active at the time this block was mined + let selected_quorums = quorum_set.select_quorums(signing_height, verification_height); + + if selected_quorums.is_empty() { + return Err(Error::Execution(ExecutionError::CorruptedCodeExecution( + "No quorums selected for instant lock signature verification for specified height", + ))); + }; + + let request_id = instant_lock.request_id().map_err(|e| { + Error::Serialization(SerializationError::CorruptedSerialization(format!( + "can't hash instant lock request ID for signature verification: {e}" + ))) + })?; + + for (i, quorums) in selected_quorums.enumerate() { + let Some((quorum_hash, quorum)) = quorums.choose_quorum(request_id.as_ref()) else { + if tracing::enabled!(tracing::Level::TRACE) { + tracing::trace!( + quorums_iteration = i + 1, + instant_lock = ?InstantLockDebug(instant_lock), + request_id = request_id.to_string(), + quorums = ?quorums.quorums, + request_id = request_id.to_string(), + signing_height, + verification_height, + "No chosen for instant Lock {} request ID {}", + instant_lock.txid, + request_id, + ); + }; + + continue; + }; + + // The signature must verify against the quorum public key and SHA256(llmqType, quorumHash, SHA256(height), txId). + // llmqType and quorumHash must be taken from the quorum selected in 1. + let mut engine = sha256d::Hash::engine(); + + let mut reversed_quorum_hash = quorum_hash.to_byte_array().to_vec(); + reversed_quorum_hash.reverse(); + + engine.input(&[quorum_set.config().quorum_type as u8]); + engine.input(reversed_quorum_hash.as_slice()); + engine.input(request_id.as_byte_array()); + engine.input(instant_lock.txid.as_byte_array()); + + let message_digest = sha256d::Hash::from_engine(engine); + + if quorum + .public_key + .verify(&signature, message_digest.as_ref()) + { + return Ok(true); + } + + if tracing::enabled!(tracing::Level::TRACE) { + tracing::trace!( + quorums_iteration = i + 1, + instant_lock = ?InstantLockDebug(instant_lock), + quorum_hash = quorum_hash.to_string(), + quorum_config = ?quorum_set.config(), + quorum = ?quorum, + request_id = request_id.to_string(), + message_digest = message_digest.to_string(), + signing_height, + verification_height, + "Instant Lock {} signature verification failed", + instant_lock.txid, + ); + }; + } + + Ok(false) +} + +// TODO: The best way is to implement Value trait for InstantLock and hashes +// in dashcore + +/// An additional struct to implement Debug for InstantLock with hex strings +/// instead of byte arrays +struct InstantLockDebug<'a>(&'a InstantLock); + +impl<'a> Debug for InstantLockDebug<'a> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + let instant_lock = &self.0; + f.debug_struct("InstantLock") + .field("version", &instant_lock.version) + .field( + "inputs", + &instant_lock + .inputs + .iter() + .map(|input| input.to_string()) + .collect::>(), + ) + .field("txid", &instant_lock.txid.to_string()) + .field("cyclehash", &instant_lock.cyclehash.to_string()) + .field("signature", &instant_lock.signature.to_string()) + .finish() + } +} diff --git a/packages/rs-drive-abci/src/execution/platform_events/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/mod.rs index 79821827bea..d63103d880d 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/mod.rs @@ -26,3 +26,6 @@ pub(in crate::execution) mod block_start; /// Verify the chain lock pub(in crate::execution) mod core_chain_lock; + +/// Instant lock methods +pub(in crate::execution) mod core_instant_send_lock; diff --git a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs index 29827900d00..a9ba48da712 100644 --- a/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs +++ b/packages/rs-drive-abci/src/execution/platform_events/state_transition_processing/process_raw_state_transitions/v0/mod.rs @@ -214,6 +214,19 @@ where // the first error must be present for an invalid result .remove(0); + if tracing::enabled!(tracing::Level::DEBUG) { + let st_hash = hex::encode(hash_single(raw_state_transition)); + + tracing::debug!( + error = ?first_consensus_error, + st_hash, + "Invalid {} state transition without identity ({}): {}", + state_transition_name, + st_hash, + &first_consensus_error + ); + } + // We don't have execution event, so we can't pay for processing return Ok(StateTransitionExecutionResult::UnpaidConsensusError( first_consensus_error, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/common/asset_lock/proof/validate/instant/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/common/asset_lock/proof/validate/instant/mod.rs index e9fb84b8f8d..a2500b06636 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/common/asset_lock/proof/validate/instant/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/common/asset_lock/proof/validate/instant/mod.rs @@ -1,7 +1,6 @@ use crate::error::Error; use crate::platform_types::platform::PlatformRef; use crate::rpc::core::CoreRPCLike; -use crate::rpc::signature::CoreSignatureVerification; use dpp::asset_lock::reduced_asset_lock_value::AssetLockValue; use dpp::consensus::basic::identity::InvalidInstantAssetLockProofSignatureError; use dpp::fee::Credits; @@ -11,10 +10,10 @@ use dpp::state_transition::signable_bytes_hasher::SignableBytesHasher; use dpp::validation::ConsensusValidationResult; use dpp::version::PlatformVersion; use drive::grovedb::TransactionArg; +use crate::execution::platform_events::core_instant_send_lock::verify_recent_signature_locally::VerifyInstantLockSignature; use crate::execution::validation::state_transition::common::asset_lock::proof::validate::AssetLockProofValidation; use crate::execution::validation::state_transition::common::asset_lock::proof::verify_is_not_spent::AssetLockProofVerifyIsNotSpent; use crate::execution::validation::state_transition::ValidationMode; -use crate::platform_types::platform_state::v0::PlatformStateV0Methods; // TODO: Versioning impl AssetLockProofValidation for InstantAssetLockProof { @@ -45,12 +44,29 @@ impl AssetLockProofValidation for InstantAssetLockProof { // As we know this outpoint was already considered final and locked. if validation_mode != ValidationMode::RecheckTx && !validation_result.has_data() { - let is_instant_lock_signature_valid = self.instant_lock().verify_signature( - platform_ref.core_rpc, - platform_ref.state.last_committed_core_height(), - )?; + // We should be able to disable instant lock versification for integration tests + #[cfg(feature = "testing-config")] + if platform_ref + .config + .testing_configs + .disable_instant_lock_signature_verification + { + return Ok(validation_result); + } + + // TODO: Shouldn't we add an operation for fees? + + // This is a limited verification and will work properly only for recently signed instant locks. + // Even valid instant locks that was signed some time ago will be considered invalid due to limited + // quorum information in the platform state. In turn, this verification doesn't use Core RPC or any other + // IO. This is done to prevent DoS attacks on slow verify instant lock signature Core RPC method. + // In case of failed signature verification (or any knowing the fact that signing quorum is old), + // we expect clients to use ChainAssetLockProof. + let is_valid = self + .instant_lock() + .verify_recent_signature_locally(platform_ref.state, platform_version)?; - if !is_instant_lock_signature_valid { + if !is_valid { return Ok(ConsensusValidationResult::new_with_error( InvalidInstantAssetLockProofSignatureError::new().into(), )); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs index dffa542954d..ae6e797a544 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/data_contract_update/mod.rs @@ -52,12 +52,11 @@ impl StateTransitionActionTransformerV0 for DataContractUpdateTransition { #[cfg(test)] mod tests { - use crate::config::{ExecutionConfig, PlatformConfig, PlatformTestConfig}; + use crate::config::{ExecutionConfig, PlatformConfig, PlatformTestConfig, ValidatorSetConfig}; use crate::platform_types::platform::PlatformRef; use crate::rpc::core::MockCoreRPCLike; use crate::test::helpers::setup::{TempPlatform, TestPlatformBuilder}; use dpp::block::block_info::BlockInfo; - use dpp::consensus::basic::BasicError; use dpp::consensus::state::state_error::StateError; use dpp::consensus::ConsensusError; use dpp::dash_to_credits; @@ -174,7 +173,10 @@ mod tests { .data_contract_owned(); let config = PlatformConfig { - validator_set_quorum_size: 10, + validator_set: ValidatorSetConfig { + quorum_size: 10, + ..Default::default() + }, execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_create/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_create/mod.rs index f68781b6b13..a7db42dc744 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_create/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_create/mod.rs @@ -193,6 +193,7 @@ impl StateTransitionStateValidationForIdentityCreateTransitionV0 for IdentityCre #[cfg(test)] mod tests { + use crate::config::{PlatformConfig, PlatformTestConfig}; use crate::test::helpers::setup::TestPlatformBuilder; use dpp::block::block_info::BlockInfo; use dpp::dashcore::{Network, PrivateKey}; @@ -215,15 +216,19 @@ mod tests { #[test] fn test_identity_create_validation() { let platform_version = PlatformVersion::latest(); - let mut platform = TestPlatformBuilder::new() + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) .build_with_mock_rpc() .set_initial_state_structure(); - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); - let platform_state = platform.state.load(); let mut signer = SimpleSigner::default(); @@ -322,15 +327,19 @@ mod tests { #[test] fn test_identity_create_asset_lock_reuse_after_issue() { let platform_version = PlatformVersion::latest(); - let mut platform = TestPlatformBuilder::new() + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) .build_with_mock_rpc() .set_initial_state_structure(); - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); - let platform_state = platform.state.load(); let mut signer = SimpleSigner::default(); @@ -536,15 +545,19 @@ mod tests { #[test] fn test_identity_create_asset_lock_reuse_after_max_issues() { let platform_version = PlatformVersion::latest(); - let mut platform = TestPlatformBuilder::new() + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) .build_with_mock_rpc() .set_initial_state_structure(); - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); - let platform_state = platform.state.load(); let mut signer = SimpleSigner::default(); @@ -756,15 +769,19 @@ mod tests { #[test] fn test_identity_create_asset_lock_use_all_funds() { let platform_version = PlatformVersion::latest(); - let mut platform = TestPlatformBuilder::new() + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) .build_with_mock_rpc() .set_initial_state_structure(); - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); - let platform_state = platform.state.load(); let mut signer = SimpleSigner::default(); @@ -977,15 +994,19 @@ mod tests { #[test] fn test_identity_create_asset_lock_replay_attack() { let platform_version = PlatformVersion::latest(); - let mut platform = TestPlatformBuilder::new() + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) .build_with_mock_rpc() .set_initial_state_structure(); - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); - let platform_state = platform.state.load(); let mut signer = SimpleSigner::default(); diff --git a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_top_up/mod.rs b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_top_up/mod.rs index 670a1ac80cb..7bfa108e724 100644 --- a/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_top_up/mod.rs +++ b/packages/rs-drive-abci/src/execution/validation/state_transition/state_transitions/identity_top_up/mod.rs @@ -100,6 +100,7 @@ impl StateTransitionBasicStructureValidationV0 for IdentityTopUpTransition { #[cfg(test)] mod tests { + use crate::config::{PlatformConfig, PlatformTestConfig}; use crate::test::helpers::setup::TestPlatformBuilder; use dpp::block::block_info::BlockInfo; use dpp::dashcore::{Network, PrivateKey}; @@ -121,15 +122,19 @@ mod tests { #[test] fn test_identity_top_up_validation() { let platform_version = PlatformVersion::latest(); - let mut platform = TestPlatformBuilder::new() + let platform_config = PlatformConfig { + testing_configs: PlatformTestConfig { + disable_instant_lock_signature_verification: true, + ..Default::default() + }, + ..Default::default() + }; + + let platform = TestPlatformBuilder::new() + .with_config(platform_config) .build_with_mock_rpc() .set_initial_state_structure(); - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); - let platform_state = platform.state.load(); let mut signer = SimpleSigner::default(); diff --git a/packages/rs-drive-abci/src/mimic/mod.rs b/packages/rs-drive-abci/src/mimic/mod.rs index d548590106a..a691cd47724 100644 --- a/packages/rs-drive-abci/src/mimic/mod.rs +++ b/packages/rs-drive-abci/src/mimic/mod.rs @@ -457,7 +457,7 @@ impl<'a, C: CoreRPCLike> FullAbciApplication<'a, C> { // We need to sign the block - let quorum_type = self.platform.config.validator_set_quorum_type(); + let quorum_type = self.platform.config.validator_set.quorum_type; let state_id_hash = state_id .calculate_msg_hash(CHAIN_ID, height as i64, round as i32) .expect("cannot calculate state id hash"); @@ -480,7 +480,13 @@ impl<'a, C: CoreRPCLike> FullAbciApplication<'a, C> { threshold_vote_extensions: extensions, }; //if not in testing this will default to true - if self.platform.config.testing_configs.block_signing { + #[cfg(not(feature = "testing-config"))] + let sign_block = true; + + #[cfg(feature = "testing-config")] + let sign_block = self.platform.config.testing_configs.block_signing; + + if sign_block { let quorum_hash: [u8; 32] = quorum_hash.try_into().expect("wrong quorum hash len"); let digest = commit .calculate_sign_hash( diff --git a/packages/rs-drive-abci/src/mimic/test_quorum.rs b/packages/rs-drive-abci/src/mimic/test_quorum.rs index e32888457bc..c1653183c6d 100644 --- a/packages/rs-drive-abci/src/mimic/test_quorum.rs +++ b/packages/rs-drive-abci/src/mimic/test_quorum.rs @@ -95,6 +95,8 @@ pub struct TestQuorumInfo { pub core_height: u32, /// The hash of the quorum. pub quorum_hash: QuorumHash, + /// The quorum index. Available only for DIP24 rotated quorums. + pub quorum_index: Option, /// The set of validators that belong to the quorum. pub validator_set: Vec, /// A map of validators indexed by their `ProTxHash` identifiers. @@ -129,6 +131,7 @@ impl TestQuorumInfo { pub fn from_quorum_hash_and_pro_tx_hashes( core_height: u32, quorum_hash: QuorumHash, + quorum_index: Option, pro_tx_hashes: Vec, rng: &mut StdRng, ) -> Self { @@ -172,6 +175,7 @@ impl TestQuorumInfo { TestQuorumInfo { core_height, quorum_hash, + quorum_index, validator_set, validator_map: map, private_key: recovered_private_key, @@ -185,6 +189,7 @@ impl From<&TestQuorumInfo> for ValidatorSetV0 { let TestQuorumInfo { core_height, quorum_hash, + quorum_index, validator_set, private_key: _, public_key, @@ -199,6 +204,7 @@ impl From<&TestQuorumInfo> for ValidatorSetV0 { .map(|v| (v.pro_tx_hash, v.into())) .collect(), threshold_public_key: public_key.clone(), + quorum_index: *quorum_index, } } } @@ -208,6 +214,7 @@ impl From for ValidatorSetV0 { let TestQuorumInfo { core_height, quorum_hash, + quorum_index, validator_set, private_key: _, public_key, @@ -216,6 +223,7 @@ impl From for ValidatorSetV0 { ValidatorSetV0 { quorum_hash, + quorum_index, core_height, members: validator_set .iter() diff --git a/packages/rs-drive-abci/src/platform_types/mod.rs b/packages/rs-drive-abci/src/platform_types/mod.rs index 66a86cbbee2..f6e9b3f838e 100644 --- a/packages/rs-drive-abci/src/platform_types/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/mod.rs @@ -47,8 +47,8 @@ pub mod platform; pub mod platform_state; /// Required identity public key set for system identities pub mod required_identity_public_key_set; -/// Signature verification quorums -pub mod signature_verification_quorums; +/// Signature verification quorums for Core +pub mod signature_verification_quorum_set; /// The state transition execution result as part of the block execution outcome pub mod state_transitions_processing_result; /// System identity public keys diff --git a/packages/rs-drive-abci/src/platform_types/platform/mod.rs b/packages/rs-drive-abci/src/platform_types/platform/mod.rs index 3cab0f01fc8..24c2dba3df8 100644 --- a/packages/rs-drive-abci/src/platform_types/platform/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform/mod.rs @@ -249,7 +249,8 @@ impl Platform { let platform_state = PlatformState::default_with_protocol_versions( current_protocol_version_in_consensus, next_epoch_protocol_version, - ); + &config, + )?; let height = platform_state.last_committed_block_height(); diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs index be67bdb11e4..d92a5a00c88 100644 --- a/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform_state/mod.rs @@ -20,8 +20,9 @@ use dpp::version::{PlatformVersion, TryFromPlatformVersioned, TryIntoPlatformVer use dpp::ProtocolError; use indexmap::IndexMap; +use crate::config::PlatformConfig; use crate::error::execution::ExecutionError; -use crate::platform_types::signature_verification_quorums::SignatureVerificationQuorums; +use crate::platform_types::signature_verification_quorum_set::SignatureVerificationQuorumSet; use dpp::block::block_info::BlockInfo; use dpp::util::hash::hash_double; use std::collections::BTreeMap; @@ -119,13 +120,17 @@ impl PlatformState { pub fn default_with_protocol_versions( current_protocol_version_in_consensus: ProtocolVersion, next_epoch_protocol_version: ProtocolVersion, - ) -> PlatformState { + config: &PlatformConfig, + ) -> Result { //todo find the current Platform state for the protocol version - PlatformStateV0::default_with_protocol_versions( + let state = PlatformStateV0::default_with_protocol_versions( current_protocol_version_in_consensus, next_epoch_protocol_version, - ) - .into() + config, + )? + .into(); + + Ok(state) } /// Retrieve version 0, or an error if not currently on version 0 @@ -316,7 +321,7 @@ impl PlatformStateV0Methods for PlatformState { } } - fn chain_lock_validating_quorums(&self) -> &SignatureVerificationQuorums { + fn chain_lock_validating_quorums(&self) -> &SignatureVerificationQuorumSet { match self { PlatformState::V0(v0) => &v0.chain_lock_validating_quorums, } @@ -382,12 +387,18 @@ impl PlatformStateV0Methods for PlatformState { } } - fn set_chain_lock_validating_quorums(&mut self, quorums: SignatureVerificationQuorums) { + fn set_chain_lock_validating_quorums(&mut self, quorums: SignatureVerificationQuorumSet) { match self { PlatformState::V0(v0) => v0.set_chain_lock_validating_quorums(quorums), } } + fn set_instant_lock_validating_quorums(&mut self, quorums: SignatureVerificationQuorumSet) { + match self { + PlatformState::V0(v0) => v0.set_instant_lock_validating_quorums(quorums), + } + } + fn set_full_masternode_list(&mut self, list: BTreeMap) { match self { PlatformState::V0(v0) => v0.set_full_masternode_list(list), @@ -442,7 +453,7 @@ impl PlatformStateV0Methods for PlatformState { } } - fn chain_lock_validating_quorums_mut(&mut self) -> &mut SignatureVerificationQuorums { + fn chain_lock_validating_quorums_mut(&mut self) -> &mut SignatureVerificationQuorumSet { match self { PlatformState::V0(v0) => v0.chain_lock_validating_quorums_mut(), } @@ -471,4 +482,16 @@ impl PlatformStateV0Methods for PlatformState { PlatformState::V0(v0) => v0.last_committed_block_id_hash(), } } + + fn instant_lock_validating_quorums(&self) -> &SignatureVerificationQuorumSet { + match self { + PlatformState::V0(v0) => v0.instant_lock_validating_quorums(), + } + } + + fn instant_lock_validating_quorums_mut(&mut self) -> &mut SignatureVerificationQuorumSet { + match self { + PlatformState::V0(v0) => v0.instant_lock_validating_quorums_mut(), + } + } } diff --git a/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs index 4a9da76867f..2c22025628b 100644 --- a/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/platform_state/v0/mod.rs @@ -19,7 +19,10 @@ use dpp::block::block_info::{BlockInfo, DEFAULT_BLOCK_INFO}; use dpp::block::extended_block_info::v0::ExtendedBlockInfoV0Getters; use dpp::version::{PlatformVersion, TryIntoPlatformVersioned}; -use crate::platform_types::signature_verification_quorums::SignatureVerificationQuorums; +use crate::config::PlatformConfig; +use crate::platform_types::signature_verification_quorum_set::{ + SignatureVerificationQuorumSet, SignatureVerificationQuorumSetForSaving, +}; use itertools::Itertools; use std::collections::BTreeMap; use std::fmt::{Debug, Formatter}; @@ -44,8 +47,11 @@ pub struct PlatformStateV0 { /// all members pub validator_sets: IndexMap, - /// The current quorums used for validating chain locks (400 60 for mainnet) - pub chain_lock_validating_quorums: SignatureVerificationQuorums, + /// Quorums used for validating chain locks (400 60 for mainnet) + pub chain_lock_validating_quorums: SignatureVerificationQuorumSet, + + /// Quorums used for validating instant locks + pub instant_lock_validating_quorums: SignatureVerificationQuorumSet, /// current full masternode list pub full_masternode_list: BTreeMap, @@ -89,6 +95,10 @@ impl Debug for PlatformStateV0 { "chain_lock_validating_quorums", &self.chain_lock_validating_quorums, ) + .field( + "instant_lock_validating_quorums", + &self.instant_lock_validating_quorums, + ) .finish() } } @@ -122,8 +132,11 @@ pub struct PlatformStateForSavingV0 { #[bincode(with_serde)] pub validator_sets: Vec<(Bytes32, ValidatorSet)>, - /// The 400 60 quorums used for validating chain locks - pub chain_lock_validating_quorums: SignatureVerificationQuorums, + /// The quorums used for validating chain locks + pub chain_lock_validating_quorums: SignatureVerificationQuorumSetForSaving, + + /// The quorums used for validating instant locks + pub instant_lock_validating_quorums: SignatureVerificationQuorumSetForSaving, /// current full masternode list pub full_masternode_list: BTreeMap, @@ -154,7 +167,8 @@ impl TryFrom for PlatformStateForSavingV0 { .into_iter() .map(|(k, v)| (k.to_byte_array().into(), v)) .collect(), - chain_lock_validating_quorums: value.chain_lock_validating_quorums, + chain_lock_validating_quorums: value.chain_lock_validating_quorums.into(), + instant_lock_validating_quorums: value.instant_lock_validating_quorums.into(), full_masternode_list: value .full_masternode_list .into_iter() @@ -197,7 +211,8 @@ impl From for PlatformStateV0 { .into_iter() .map(|(k, v)| (QuorumHash::from_byte_array(k.to_buffer()), v)) .collect(), - chain_lock_validating_quorums: value.chain_lock_validating_quorums, + chain_lock_validating_quorums: value.chain_lock_validating_quorums.into(), + instant_lock_validating_quorums: value.instant_lock_validating_quorums.into(), full_masternode_list: value .full_masternode_list .into_iter() @@ -217,23 +232,31 @@ impl PlatformStateV0 { pub(super) fn default_with_protocol_versions( current_protocol_version_in_consensus: ProtocolVersion, next_epoch_protocol_version: ProtocolVersion, - ) -> PlatformStateV0 { - let platform_version = PlatformVersion::get(current_protocol_version_in_consensus) - .expect("invalid protocol version"); + config: &PlatformConfig, + ) -> Result { + let platform_version = PlatformVersion::get(current_protocol_version_in_consensus)?; - PlatformStateV0 { + let state = PlatformStateV0 { last_committed_block_info: None, current_protocol_version_in_consensus, next_epoch_protocol_version, current_validator_set_quorum_hash: QuorumHash::all_zeros(), next_validator_set_quorum_hash: None, validator_sets: Default::default(), - chain_lock_validating_quorums: - SignatureVerificationQuorums::default_for_platform_version(platform_version), + chain_lock_validating_quorums: SignatureVerificationQuorumSet::new( + &config.chain_lock, + platform_version, + )?, + instant_lock_validating_quorums: SignatureVerificationQuorumSet::new( + &config.instant_lock, + platform_version, + )?, full_masternode_list: Default::default(), hpmn_masternode_list: Default::default(), genesis_block_info: None, - } + }; + + Ok(state) } } @@ -283,8 +306,11 @@ pub trait PlatformStateV0Methods { /// Returns the current validator sets. fn validator_sets(&self) -> &IndexMap; - /// Returns the current 400 60 quorums used to validate chain locks. - fn chain_lock_validating_quorums(&self) -> &SignatureVerificationQuorums; + /// Returns the quorums used to validate chain locks. + fn chain_lock_validating_quorums(&self) -> &SignatureVerificationQuorumSet; + + /// Returns quorums used to validate instant locks. + fn instant_lock_validating_quorums(&self) -> &SignatureVerificationQuorumSet; /// Returns the full list of masternodes. fn full_masternode_list(&self) -> &BTreeMap; @@ -317,7 +343,10 @@ pub trait PlatformStateV0Methods { fn set_validator_sets(&mut self, sets: IndexMap); /// Sets the current chain lock validating quorums. - fn set_chain_lock_validating_quorums(&mut self, quorums: SignatureVerificationQuorums); + fn set_chain_lock_validating_quorums(&mut self, quorums: SignatureVerificationQuorumSet); + + /// Sets the current instant lock validating quorums. + fn set_instant_lock_validating_quorums(&mut self, quorums: SignatureVerificationQuorumSet); /// Sets the full masternode list. fn set_full_masternode_list(&mut self, list: BTreeMap); @@ -345,8 +374,11 @@ pub trait PlatformStateV0Methods { /// Returns a mutable reference to the current validator sets. fn validator_sets_mut(&mut self) -> &mut IndexMap; - /// Returns a mutable reference to the current chain lock validating quorums. - fn chain_lock_validating_quorums_mut(&mut self) -> &mut SignatureVerificationQuorums; + /// Returns a mutable reference to the chain lock validating quorums. + fn chain_lock_validating_quorums_mut(&mut self) -> &mut SignatureVerificationQuorumSet; + + /// Returns a mutable reference to the instant lock validating quorums. + fn instant_lock_validating_quorums_mut(&mut self) -> &mut SignatureVerificationQuorumSet; /// Returns a mutable reference to the full masternode list. fn full_masternode_list_mut(&mut self) -> &mut BTreeMap; @@ -499,11 +531,16 @@ impl PlatformStateV0Methods for PlatformStateV0 { &self.validator_sets } - /// Returns the current 400 60 quorums used to validate chain locks. - fn chain_lock_validating_quorums(&self) -> &SignatureVerificationQuorums { + /// Returns the quorums used to validate chain locks. + fn chain_lock_validating_quorums(&self) -> &SignatureVerificationQuorumSet { &self.chain_lock_validating_quorums } + /// Returns the quorums used to validate instant locks. + fn instant_lock_validating_quorums(&self) -> &SignatureVerificationQuorumSet { + &self.instant_lock_validating_quorums + } + /// Returns the full list of masternodes. fn full_masternode_list(&self) -> &BTreeMap { &self.full_masternode_list @@ -561,10 +598,15 @@ impl PlatformStateV0Methods for PlatformStateV0 { } /// Sets the current chain lock validating quorums. - fn set_chain_lock_validating_quorums(&mut self, quorums: SignatureVerificationQuorums) { + fn set_chain_lock_validating_quorums(&mut self, quorums: SignatureVerificationQuorumSet) { self.chain_lock_validating_quorums = quorums; } + /// Sets the current instant lock validating quorums. + fn set_instant_lock_validating_quorums(&mut self, quorums: SignatureVerificationQuorumSet) { + self.instant_lock_validating_quorums = quorums; + } + /// Sets the full masternode list. fn set_full_masternode_list(&mut self, list: BTreeMap) { self.full_masternode_list = list; @@ -604,10 +646,14 @@ impl PlatformStateV0Methods for PlatformStateV0 { &mut self.validator_sets } - fn chain_lock_validating_quorums_mut(&mut self) -> &mut SignatureVerificationQuorums { + fn chain_lock_validating_quorums_mut(&mut self) -> &mut SignatureVerificationQuorumSet { &mut self.chain_lock_validating_quorums } + fn instant_lock_validating_quorums_mut(&mut self) -> &mut SignatureVerificationQuorumSet { + &mut self.instant_lock_validating_quorums + } + fn full_masternode_list_mut(&mut self) -> &mut BTreeMap { &mut self.full_masternode_list } diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/mod.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/mod.rs new file mode 100644 index 00000000000..8d0eac3c0a3 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/mod.rs @@ -0,0 +1,141 @@ +mod v0; + +use crate::config::QuorumLikeConfig; +use crate::error::execution::ExecutionError; +use crate::error::Error; +use crate::platform_types::signature_verification_quorum_set::v0::for_saving::SignatureVerificationQuorumSetForSavingV0; +pub use crate::platform_types::signature_verification_quorum_set::v0::quorum_set::{ + QuorumConfig, QuorumsWithConfig, SelectedQuorumSetIterator, SignatureVerificationQuorumSetV0, + SignatureVerificationQuorumSetV0Methods, SIGN_OFFSET, +}; +pub use crate::platform_types::signature_verification_quorum_set::v0::quorums::{ + Quorum, Quorums, SigningQuorum, ThresholdBlsPublicKey, VerificationQuorum, +}; +use bincode::{Decode, Encode}; +use derive_more::From; +use dpp::version::PlatformVersion; + +/// Quorums with keys for signature verification +#[derive(Debug, Clone, From)] +pub enum SignatureVerificationQuorumSet { + /// Version 0 of the signature verification quorums + V0(SignatureVerificationQuorumSetV0), +} + +impl SignatureVerificationQuorumSet { + /// Create a default SignatureVerificationQuorums + pub fn new( + config: &impl QuorumLikeConfig, + platform_version: &PlatformVersion, + ) -> Result { + match platform_version + .drive_abci + .structs + .signature_verification_quorum_set + { + 0 => Ok(SignatureVerificationQuorumSetV0::new(config).into()), + version => Err(Error::Execution(ExecutionError::UnknownVersionMismatch { + method: "SignatureVerificationQuorumSet.new".to_string(), + known_versions: vec![0], + received: version, + })), + } + } +} + +impl SignatureVerificationQuorumSetV0Methods for SignatureVerificationQuorumSet { + fn config(&self) -> &QuorumConfig { + match self { + Self::V0(v0) => v0.config(), + } + } + + fn set_current_quorums(&mut self, quorums: Quorums) { + match self { + Self::V0(v0) => v0.set_current_quorums(quorums), + } + } + + fn current_quorums(&self) -> &Quorums { + match self { + Self::V0(v0) => v0.current_quorums(), + } + } + + fn current_quorums_mut(&mut self) -> &mut Quorums { + match self { + Self::V0(v0) => v0.current_quorums_mut(), + } + } + + fn has_previous_past_quorums(&self) -> bool { + match self { + Self::V0(v0) => v0.has_previous_past_quorums(), + } + } + + fn replace_quorums( + &mut self, + quorums: Quorums, + last_active_core_height: u32, + updated_at_core_height: u32, + ) { + match self { + Self::V0(v0) => { + v0.replace_quorums(quorums, last_active_core_height, updated_at_core_height) + } + } + } + + fn set_previous_past_quorums( + &mut self, + previous_quorums: Quorums, + last_active_core_height: u32, + updated_at_core_height: u32, + ) { + match self { + Self::V0(v0) => v0.set_previous_past_quorums( + previous_quorums, + last_active_core_height, + updated_at_core_height, + ), + } + } + + fn select_quorums( + &self, + signing_height: u32, + verification_height: u32, + ) -> SelectedQuorumSetIterator { + match self { + Self::V0(v0) => v0.select_quorums(signing_height, verification_height), + } + } +} + +/// Core Quorum Set structure for saving to the database +#[derive(Debug, Clone, Encode, Decode)] +pub enum SignatureVerificationQuorumSetForSaving { + /// Version 0 of the signature verification quorums + V0(SignatureVerificationQuorumSetForSavingV0), +} + +impl From for SignatureVerificationQuorumSetForSaving { + fn from(value: SignatureVerificationQuorumSet) -> Self { + match value { + SignatureVerificationQuorumSet::V0(v0) => { + SignatureVerificationQuorumSetForSaving::V0(v0.into()) + } + } + } +} + +impl From for SignatureVerificationQuorumSet { + fn from(value: SignatureVerificationQuorumSetForSaving) -> Self { + match value { + SignatureVerificationQuorumSetForSaving::V0(v0) => { + SignatureVerificationQuorumSet::V0(v0.into()) + } + } + } +} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs new file mode 100644 index 00000000000..5e254e62023 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs @@ -0,0 +1,167 @@ +use crate::platform_types::signature_verification_quorum_set::v0::quorum_set::{ + PreviousPastQuorumsV0, QuorumConfig, +}; +use crate::platform_types::signature_verification_quorum_set::{ + Quorums, SignatureVerificationQuorumSetForSaving, SignatureVerificationQuorumSetV0, + ThresholdBlsPublicKey, VerificationQuorum, +}; +use dashcore_rpc::dashcore::hashes::Hash; +use dashcore_rpc::dashcore::QuorumHash; +use dashcore_rpc::json::QuorumType; +use dpp::identity::state_transition::asset_lock_proof::Encode; +use dpp::platform_serialization::de::Decode; +use dpp::platform_value::Bytes32; + +#[derive(Debug, Clone, Encode, Decode)] +pub struct SignatureVerificationQuorumSetForSavingV0 { + config: QuorumConfigForSavingV0, + current_quorums: Vec, + previous_quorums: Option, +} + +impl From for SignatureVerificationQuorumSetForSaving { + fn from(value: SignatureVerificationQuorumSetForSavingV0) -> Self { + SignatureVerificationQuorumSetForSaving::V0(value) + } +} + +impl From for SignatureVerificationQuorumSetForSavingV0 { + fn from(value: SignatureVerificationQuorumSetV0) -> Self { + let SignatureVerificationQuorumSetV0 { + config, + current_quorums, + previous, + } = value; + + Self { + config: config.into(), + current_quorums: current_quorums.into(), + previous_quorums: previous.map(|previous| previous.into()), + } + } +} + +impl From for SignatureVerificationQuorumSetV0 { + fn from(value: SignatureVerificationQuorumSetForSavingV0) -> Self { + let SignatureVerificationQuorumSetForSavingV0 { + config, + current_quorums, + previous_quorums, + } = value; + + Self { + config: config.into(), + current_quorums: current_quorums.into(), + previous: previous_quorums.map(|previous| previous.into()), + } + } +} + +#[derive(Debug, Clone, Encode, Decode)] +pub struct QuorumConfigForSavingV0 { + quorum_type: QuorumType, + active_signers: u16, + rotation: bool, + window: u32, +} + +impl From for QuorumConfigForSavingV0 { + fn from(config: QuorumConfig) -> Self { + Self { + quorum_type: config.quorum_type, + active_signers: config.active_signers, + rotation: config.rotation, + window: config.window, + } + } +} + +impl From for QuorumConfig { + fn from(config: QuorumConfigForSavingV0) -> Self { + Self { + quorum_type: config.quorum_type, + active_signers: config.active_signers, + rotation: config.rotation, + window: config.window, + } + } +} + +#[derive(Debug, Clone, Encode, Decode)] +pub struct PreviousPastQuorumsForSavingV0 { + quorums: Vec, + active_core_height: u32, + updated_at_core_height: u32, + previous_change_height: Option, +} + +impl From for PreviousPastQuorumsForSavingV0 { + fn from(value: PreviousPastQuorumsV0) -> Self { + let PreviousPastQuorumsV0 { + quorums, + active_core_height, + updated_at_core_height, + previous_change_height, + } = value; + + Self { + quorums: quorums.into(), + active_core_height, + updated_at_core_height, + previous_change_height, + } + } +} + +impl From for PreviousPastQuorumsV0 { + fn from(value: PreviousPastQuorumsForSavingV0) -> Self { + let PreviousPastQuorumsForSavingV0 { + quorums, + active_core_height, + updated_at_core_height, + previous_change_height, + } = value; + + Self { + quorums: quorums.into(), + active_core_height, + updated_at_core_height, + previous_change_height, + } + } +} + +#[derive(Debug, Clone, Encode, Decode)] +pub struct QuorumForSavingV0 { + hash: Bytes32, + #[bincode(with_serde)] + public_key: ThresholdBlsPublicKey, + index: Option, +} + +impl From> for Quorums { + fn from(value: Vec) -> Self { + Quorums::from_iter(value.into_iter().map(|quorum| { + ( + QuorumHash::from_byte_array(quorum.hash.to_buffer()), + VerificationQuorum { + public_key: quorum.public_key, + index: quorum.index, + }, + ) + })) + } +} + +#[allow(clippy::from_over_into)] +impl Into> for Quorums { + fn into(self) -> Vec { + self.into_iter() + .map(|(hash, quorum)| QuorumForSavingV0 { + hash: Bytes32::from(hash.as_byte_array()), + public_key: quorum.public_key, + index: quorum.index, + }) + .collect() + } +} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/mod.rs new file mode 100644 index 00000000000..e78d6c1c7f4 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/mod.rs @@ -0,0 +1,3 @@ +pub mod for_saving; +pub mod quorum_set; +pub mod quorums; diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorum_set.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorum_set.rs new file mode 100644 index 00000000000..9225ced3164 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorum_set.rs @@ -0,0 +1,296 @@ +use crate::config::{ChainLockConfig, QuorumLikeConfig}; +use crate::platform_types::signature_verification_quorum_set::v0::quorums::Quorums; +use crate::platform_types::signature_verification_quorum_set::VerificationQuorum; +use dashcore_rpc::json::QuorumType; +use dpp::dashcore::QuorumHash; +use std::vec::IntoIter; + +/// Offset for signature verification +pub const SIGN_OFFSET: u32 = 8; + +/// Previously obtained quorums and heights. Required for signature verification +#[derive(Debug, Clone)] +pub(super) struct PreviousPastQuorumsV0 { + pub(super) quorums: Quorums, + + /// The core height at which these quorums were last active + pub(super) active_core_height: u32, + + /// The core height when the quorums were changed + pub(super) updated_at_core_height: u32, + + /// The core height the previous chain lock validating quorums became active + pub(super) previous_change_height: Option, +} + +/// Quorums with keys for signature verification +#[derive(Debug, Clone)] +pub struct SignatureVerificationQuorumSetV0 { + /// Quorum configuration + pub(super) config: QuorumConfig, + + /// Current quorums + pub(super) current_quorums: Quorums, + + /// The slightly old quorums used for validating ch ain locks (or instant locks), it's important to keep + /// these because validation of signatures happens for the quorums that are 8 blocks before the + /// height written in the chain lock. The same for instant locks + pub(super) previous: Option, +} + +/// The trait defines methods for the signature verification quorums structure v0 +pub trait SignatureVerificationQuorumSetV0Methods { + /// Config + fn config(&self) -> &QuorumConfig; + + /// Set current quorum keys + fn set_current_quorums(&mut self, quorums: Quorums); + + /// Current quorum + fn current_quorums(&self) -> &Quorums; + + /// Last quorum keys mutable + fn current_quorums_mut(&mut self) -> &mut Quorums; + + /// Has previous quorums? + fn has_previous_past_quorums(&self) -> bool; + + /// Set last quorums keys and update previous quorums + fn replace_quorums( + &mut self, + quorums: Quorums, + last_active_core_height: u32, + updated_at_core_height: u32, + ); + + /// Update previous quorums + fn set_previous_past_quorums( + &mut self, + previous_quorums: Quorums, + last_active_core_height: u32, + updated_at_core_height: u32, + ); + + /// Select quorums for signature verification based on sign and verification heights + fn select_quorums( + &self, + signing_height: u32, + verification_height: u32, + ) -> SelectedQuorumSetIterator; +} + +/// Iterator over selected quorum sets and specific quorums based on request_id and quorum configuration +pub struct SelectedQuorumSetIterator<'q> { + /// Quorum configuration + config: &'q QuorumConfig, + /// Appropriate quorum sets + quorum_set: IntoIter<&'q Quorums>, + /// Should we expect signature verification to be successful + should_be_verifiable: bool, +} + +impl<'q> Iterator for SelectedQuorumSetIterator<'q> { + type Item = QuorumsWithConfig<'q>; + + fn next(&mut self) -> Option { + self.quorum_set.next().map(|quorums| QuorumsWithConfig { + quorums, + config: self.config, + }) + } +} + +/// Quorums with configuration +pub struct QuorumsWithConfig<'q> { + /// Quorums + pub quorums: &'q Quorums, + /// Config + pub config: &'q QuorumConfig, +} + +impl<'q> QuorumsWithConfig<'q> { + /// Choose pseudorandom DIP8 or DIP24 quorum based on quorum config + /// and request_id + pub fn choose_quorum( + &self, + request_id: &[u8; 32], + ) -> Option<(QuorumHash, &VerificationQuorum)> { + self.quorums.choose_quorum(self.config, request_id) + } +} + +impl<'q> SelectedQuorumSetIterator<'q> { + /// Number of quorum sets + pub fn len(&self) -> usize { + self.quorum_set.len() + } + + /// Does the iterator have any quorum sets + pub fn is_empty(&self) -> bool { + self.quorum_set.len() == 0 + } + + /// Should we expect signature verification to be successful + pub fn should_be_verifiable(&self) -> bool { + self.should_be_verifiable + } +} + +/// Quorum configuration +#[derive(Debug, Clone)] +pub struct QuorumConfig { + /// Type + pub quorum_type: QuorumType, + /// Active quorum signers count + pub active_signers: u16, + /// Is it a DIP24 rotating quorum or classic + pub rotation: bool, + /// DKG interval + pub window: u32, +} + +impl SignatureVerificationQuorumSetV0Methods for SignatureVerificationQuorumSetV0 { + fn config(&self) -> &QuorumConfig { + &self.config + } + + fn set_current_quorums(&mut self, quorums: Quorums) { + self.current_quorums = quorums; + } + + fn current_quorums(&self) -> &Quorums { + &self.current_quorums + } + + fn current_quorums_mut(&mut self) -> &mut Quorums { + &mut self.current_quorums + } + + fn has_previous_past_quorums(&self) -> bool { + self.previous.is_some() + } + + fn replace_quorums( + &mut self, + quorums: Quorums, + last_active_height: u32, + updated_at_core_height: u32, + ) { + let previous_quorums = std::mem::replace(&mut self.current_quorums, quorums); + + self.set_previous_past_quorums( + previous_quorums, + last_active_height, + updated_at_core_height, + ); + } + + fn set_previous_past_quorums( + &mut self, + previous_quorums: Quorums, + last_active_core_height: u32, + updated_at_core_height: u32, + ) { + self.previous = Some(PreviousPastQuorumsV0 { + quorums: previous_quorums, + active_core_height: last_active_core_height, + updated_at_core_height, + previous_change_height: self + .previous + .as_ref() + .map(|previous| previous.updated_at_core_height), + }); + } + + fn select_quorums( + &self, + signing_height: u32, + verification_height: u32, + ) -> SelectedQuorumSetIterator { + let mut quorums = Vec::new(); + let mut should_be_verifiable = false; + + if let Some(previous) = &self.previous { + let previous_quorum_height = previous.active_core_height; + let change_quorum_height = previous.updated_at_core_height; + let previous_quorums_change_height = previous.previous_change_height; + + if signing_height > SIGN_OFFSET && verification_height >= change_quorum_height { + // in this case we are sure that we should be targeting the current quorum + // We updated core chain lock height from 100 to 105, new chain lock comes in for block 114 + // ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) ------ 106 (new chain lock verification height 114 - 8) + // We are sure that we should use current quorums + // If we have + // ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) ------ 105 (new chain lock verification height 113 - 8) + // We should also use current quorums, this is because at 105 we are sure new chain lock validating quorums are active + quorums.push(&self.current_quorums); + should_be_verifiable = true; + } else if signing_height > SIGN_OFFSET && verification_height <= previous_quorum_height + { + should_be_verifiable = previous_quorums_change_height + .map(|previous_quorums_change_height| { + verification_height > previous_quorums_change_height + }) + .unwrap_or(false); + // In this case the quorums were changed recently meaning that we should use the previous quorums to verify the chain lock + // We updated core chain lock height from 100 to 105, new chain lock comes in for block 106 + // -------- 98 (new chain lock verification height 106 - 8) ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) + // We are sure that we should use previous quorums + // If we have + // -------- 100 (new chain lock verification height 108 - 8) ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) + // We should also use previous quorums, this is because at 100 we are sure the old quorum set was active + quorums.push(&previous.quorums); + } else { + should_be_verifiable = previous_quorums_change_height + .map(|previous_quorums_change_height| { + verification_height > previous_quorums_change_height + }) + .unwrap_or(false); + // we are in between, so we don't actually know if it was the old one or the new one to be used. + // ------- 100 (previous_quorum_height) ------ 104 (new chain lock verification height 112 - 8) -------105 (change_quorum_height) + // we should just try both, starting with the current quorums + quorums.push(&self.current_quorums); + quorums.push(&previous.quorums); + } + } else { + quorums.push(&self.current_quorums); + } + + SelectedQuorumSetIterator { + config: &self.config, + quorum_set: quorums.into_iter(), + should_be_verifiable, + } + } +} + +impl SignatureVerificationQuorumSetV0 { + /// New empty quorum set based on quorum configuration + pub fn new(config: &impl QuorumLikeConfig) -> Self { + SignatureVerificationQuorumSetV0 { + config: QuorumConfig { + quorum_type: config.quorum_type(), + active_signers: config.quorum_active_signers(), + rotation: config.quorum_rotation(), + window: config.quorum_window(), + }, + current_quorums: Quorums::default(), + previous: None, + } + } +} + +impl From for SignatureVerificationQuorumSetV0 { + fn from(value: ChainLockConfig) -> Self { + SignatureVerificationQuorumSetV0 { + config: QuorumConfig { + quorum_type: value.quorum_type, + active_signers: value.quorum_active_signers, + rotation: value.quorum_rotation, + window: value.quorum_window, + }, + current_quorums: Quorums::default(), + previous: None, + } + } +} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorums.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorums.rs new file mode 100644 index 00000000000..112b877a9b8 --- /dev/null +++ b/packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/quorums.rs @@ -0,0 +1,220 @@ +use derive_more::{Deref, DerefMut, From}; +use dpp::bls_signatures::PrivateKey; +use dpp::dashcore::bls_sig_utils::BLSSignature; +use dpp::dashcore::{QuorumHash, Txid}; +use std::collections::BTreeMap; +use std::convert::TryInto; +use std::fmt::Debug; + +pub use dpp::bls_signatures::PublicKey as ThresholdBlsPublicKey; + +use crate::error::Error; +use crate::platform_types::signature_verification_quorum_set::QuorumConfig; +use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; + +/// Quorum per hash +#[derive(Clone, Deref, DerefMut, From)] +pub struct Quorums(BTreeMap); + +impl Default for Quorums { + fn default() -> Self { + Quorums::(BTreeMap::new()) + } +} + +impl FromIterator<(QuorumHash, Q)> for Quorums { + fn from_iter>(iter: T) -> Self { + Quorums::(BTreeMap::from_iter(iter)) + } +} + +impl IntoIterator for Quorums { + type Item = (QuorumHash, Q); + type IntoIter = std::collections::btree_map::IntoIter; + + fn into_iter(self) -> Self::IntoIter { + self.0.into_iter() + } +} + +impl Quorums { + /// Choose pseudorandom DIP8 or DIP24 quorum based on quorum config + /// and request_id + pub fn choose_quorum( + &self, + quorum_config: &QuorumConfig, + request_id: &[u8; 32], + ) -> Option<(QuorumHash, &Q)> { + if quorum_config.rotation { + self.choose_rotating_quorum(quorum_config, request_id) + } else { + self.choose_classic_quorum(quorum_config, request_id) + } + } + + /// Based on DIP8 deterministically chooses a pseudorandom quorum from the list of quorums + fn choose_classic_quorum( + &self, + quorum_config: &QuorumConfig, + request_id: &[u8; 32], + ) -> Option<(QuorumHash, &Q)> { + // Scoring system logic + let mut scores: Vec<(&QuorumHash, &Q, [u8; 32])> = Vec::new(); + + for (quorum_hash, quorum) in self.0.iter() { + let mut quorum_hash_bytes = quorum_hash.to_byte_array().to_vec(); + + // Only the quorum hash needs reversal. + quorum_hash_bytes.reverse(); + + let mut hasher = sha256d::Hash::engine(); + + // Serialize and hash the LLMQ type + hasher.input(&[quorum_config.quorum_type as u8]); + + // Serialize and add the quorum hash + hasher.input(quorum_hash_bytes.as_slice()); + + // Serialize and add the selection hash from the chain lock + hasher.input(request_id.as_slice()); + + // Finalize the hash + let hash_result = sha256d::Hash::from_engine(hasher); + scores.push((quorum_hash, quorum, hash_result.into())); + } + + if scores.is_empty() { + return None; + } + + scores.sort_by_key(|k| k.2); + + let (quorum_hash, quorum, _) = scores.remove(0); + + Some((*quorum_hash, quorum)) + } + + /// Based on DIP24 deterministically chooses a pseudorandom quorum from the list of quorums + fn choose_rotating_quorum( + &self, + quorum_config: &QuorumConfig, + request_id: &[u8; 32], + ) -> Option<(QuorumHash, &Q)> { + let active_signers = quorum_config.active_signers as u32; + + // binary (base-2) logarithm from active_signers + let n = 31 - active_signers.leading_zeros(); + + // Extract last 64 bits of request_id + let b = u64::from_le_bytes( + request_id[24..32] + .try_into() + .expect("request_id is [u8; 32]"), + ); + + // Take last n bits of b + let mask = (1u64 << n) - 1; + let signer = (mask & (b >> (64 - n - 1))) as u32; + + self.0 + .iter() + .find(|(_, quorum)| quorum.index() == Some(signer)) + .map(|(quorum_hash, quorum)| (*quorum_hash, quorum)) + } +} + +impl Debug for Quorums { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_map() + .entries( + self.0 + .iter() + .map(|(quorum_hash, quorum)| (quorum_hash.to_string(), quorum)), + ) + .finish() + } +} + +/// Quorum trait for Quorums collection +pub trait Quorum { + /// Index is present only for rotated quorums (DIP24) + fn index(&self) -> Option; +} + +/// Quorum for signature verification +#[derive(Clone)] +pub struct VerificationQuorum { + /// Index is present only for rotated quorums (DIP24) + pub index: Option, + + /// Quorum threshold public key is used to verify + /// signatures produced by corresponding quorum + pub public_key: ThresholdBlsPublicKey, +} + +impl Debug for VerificationQuorum { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("VerificationQuorum") + .field("index", &self.index) + .field( + "public_key", + &hex::encode(*self.public_key.to_bytes()).to_string(), + ) + .finish() + } +} + +impl Quorum for VerificationQuorum { + fn index(&self) -> Option { + self.index + } +} + +/// Quorum for signature verification +#[derive(Debug, Clone)] +pub struct SigningQuorum { + /// Index is present only for rotated quorums (DIP24) + pub index: Option, + + /// Quorum private key for signing + pub private_key: [u8; 32], +} + +impl Quorum for SigningQuorum { + fn index(&self) -> Option { + self.index + } +} + +impl SigningQuorum { + /// Signs a transition for instant lock + pub fn sign_for_instant_lock( + &self, + quorum_config: &QuorumConfig, + quorum_hash: &QuorumHash, + request_id: &[u8; 32], + transaction_id: &Txid, + ) -> Result { + // The signature must verify against the quorum public key and SHA256(llmqType, quorumHash, SHA256(height), txId). + // llmqType and quorumHash must be taken from the quorum selected in 1. + let mut engine = sha256d::Hash::engine(); + + let mut reversed_quorum_hash = quorum_hash.to_byte_array().to_vec(); + reversed_quorum_hash.reverse(); + + engine.input(&[quorum_config.quorum_type as u8]); + engine.input(reversed_quorum_hash.as_slice()); + engine.input(request_id); + engine.input(transaction_id.as_byte_array()); + + let message_digest = sha256d::Hash::from_engine(engine); + + let private_key = + PrivateKey::from_bytes(&self.private_key, false).map_err(Error::BLSError)?; + + let g2element = private_key.sign(message_digest.as_ref()); + let g2element_bytes = *g2element.to_bytes(); + + Ok(BLSSignature::from(g2element_bytes)) + } +} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorums/mod.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorums/mod.rs deleted file mode 100644 index 4ad03aebc33..00000000000 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorums/mod.rs +++ /dev/null @@ -1,91 +0,0 @@ -mod v0; - -use crate::platform_types::signature_verification_quorums::v0::{ - PreviousPastQuorums, SelectedVerificationQuorumSets, -}; -use bincode::{Decode, Encode}; -use derive_more::From; -use dpp::version::PlatformVersion; -pub use v0::{ - QuorumKeysByQuorumHash, SignatureVerificationQuorumsV0, SignatureVerificationQuorumsV0Methods, -}; - -/// Quorums with keys for signature verification -#[derive(Debug, Clone, Encode, Decode, From)] -pub enum SignatureVerificationQuorums { - /// Version 0 of the signature verification quorums - V0(SignatureVerificationQuorumsV0), -} - -impl SignatureVerificationQuorums { - /// Create a default SignatureVerificationQuorums - pub fn default_for_platform_version(platform_version: &PlatformVersion) -> Self { - // TODO: default for platform version - - SignatureVerificationQuorumsV0::default().into() - } -} - -impl SignatureVerificationQuorumsV0Methods for SignatureVerificationQuorums { - fn set_current_quorums(&mut self, quorums: QuorumKeysByQuorumHash) { - match self { - Self::V0(v0) => v0.set_current_quorums(quorums), - } - } - - fn current_quorums(&self) -> &QuorumKeysByQuorumHash { - match self { - Self::V0(v0) => v0.current_quorums(), - } - } - - fn current_quorums_mut(&mut self) -> &mut QuorumKeysByQuorumHash { - match self { - Self::V0(v0) => v0.current_quorums_mut(), - } - } - - fn previous_past_quorums(&self) -> Option<&PreviousPastQuorums> { - match self { - Self::V0(v0) => v0.previous_past_quorums(), - } - } - - fn rotate_quorums( - &mut self, - quorums: QuorumKeysByQuorumHash, - last_active_core_height: u32, - updated_at_core_height: u32, - ) { - match self { - Self::V0(v0) => { - v0.rotate_quorums(quorums, last_active_core_height, updated_at_core_height) - } - } - } - - fn set_previous_past_quorums( - &mut self, - previous_quorums: QuorumKeysByQuorumHash, - last_active_core_height: u32, - updated_at_core_height: u32, - ) { - match self { - Self::V0(v0) => v0.set_previous_past_quorums( - previous_quorums, - last_active_core_height, - updated_at_core_height, - ), - } - } - - fn select_quorums( - &self, - signing_height: u32, - verification_height: u32, - ) -> SelectedVerificationQuorumSets { - match self { - Self::V0(v0) => v0.select_quorums(signing_height, verification_height), - } - } -} diff --git a/packages/rs-drive-abci/src/platform_types/signature_verification_quorums/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/signature_verification_quorums/v0/mod.rs deleted file mode 100644 index 6ab87f6f6b0..00000000000 --- a/packages/rs-drive-abci/src/platform_types/signature_verification_quorums/v0/mod.rs +++ /dev/null @@ -1,198 +0,0 @@ -use bincode::{Decode, Encode}; -use dpp::dashcore::QuorumHash; -use std::collections::{BTreeMap, VecDeque}; - -pub use dpp::bls_signatures::PublicKey as ThresholdBlsPublicKey; - -/// Quorum key per hash -pub type QuorumKeysByQuorumHash = BTreeMap; - -/// Previously obtained quorums and heights. Required for signature verification -#[derive(Debug, Clone, Encode, Decode, Default)] -pub struct PreviousPastQuorums { - /// The quorum keys by quorum hash - #[bincode(with_serde)] - quorums: QuorumKeysByQuorumHash, - - /// The core height at which these quorums were last active - active_core_height: u32, - - /// The core height when the quorums were changed - updated_at_core_height: u32, - - /// The core height the previous chain lock validating quorums became active - previous_change_height: Option, -} - -/// Quorums with keys for signature verification -#[derive(Debug, Clone, Encode, Decode, Default)] -pub struct SignatureVerificationQuorumsV0 { - /// Current quorums - #[bincode(with_serde)] - current_quorums: QuorumKeysByQuorumHash, - - /// The slightly old quorums used for validating chain locks (or instant locks), it's important to keep - /// these because validation of signatures happens for the quorums that are 8 blocks before the - /// height written in the chain lock. The same for instant locks - previous: Option, -} - -/// The trait defines methods for the signature verification quorums structure v0 -pub trait SignatureVerificationQuorumsV0Methods { - /// Set last quorum keys - fn set_current_quorums(&mut self, quorums: QuorumKeysByQuorumHash); - - /// Current quorum keys by quorum hash - fn current_quorums(&self) -> &QuorumKeysByQuorumHash; - - /// The current quorums keys mutable - fn current_quorums_mut(&mut self) -> &mut QuorumKeysByQuorumHash; - - /// Previous quorums - fn previous_past_quorums(&self) -> Option<&PreviousPastQuorums>; - - /// Set last quorums keys and update previous quorums - fn rotate_quorums( - &mut self, - quorums: QuorumKeysByQuorumHash, - last_active_core_height: u32, - updated_at_core_height: u32, - ); - - /// Set previous quorums - fn set_previous_past_quorums( - &mut self, - previous_quorums: QuorumKeysByQuorumHash, - last_active_core_height: u32, - updated_at_core_height: u32, - ); - - /// Select quorum sets for signature verification - fn select_quorums( - &self, - signing_height: u32, - verification_height: u32, - ) -> SelectedVerificationQuorumSets; -} - -pub struct SelectedVerificationQuorumSets<'q> { - pub quorum_sets: VecDeque<&'q QuorumKeysByQuorumHash>, - pub should_be_verifiable: bool, -} - -impl<'q> Iterator for SelectedVerificationQuorumSets<'q> { - type Item = &'q QuorumKeysByQuorumHash; - - fn next(&mut self) -> Option { - self.quorum_sets.pop_front() - } -} - -impl SignatureVerificationQuorumsV0Methods for SignatureVerificationQuorumsV0 { - fn set_current_quorums(&mut self, quorums: QuorumKeysByQuorumHash) { - self.current_quorums = quorums; - } - - fn current_quorums(&self) -> &QuorumKeysByQuorumHash { - &self.current_quorums - } - - fn current_quorums_mut(&mut self) -> &mut QuorumKeysByQuorumHash { - &mut self.current_quorums - } - - fn previous_past_quorums(&self) -> Option<&PreviousPastQuorums> { - self.previous.as_ref() - } - - fn rotate_quorums( - &mut self, - quorums: QuorumKeysByQuorumHash, - last_active_height: u32, - updated_at_core_height: u32, - ) { - let previous_quorums = std::mem::replace(&mut self.current_quorums, quorums); - - self.set_previous_past_quorums( - previous_quorums, - last_active_height, - updated_at_core_height, - ); - } - - fn set_previous_past_quorums( - &mut self, - previous_quorums: QuorumKeysByQuorumHash, - last_active_core_height: u32, - updated_at_core_height: u32, - ) { - self.previous = Some(PreviousPastQuorums { - quorums: previous_quorums, - active_core_height: last_active_core_height, - updated_at_core_height, - previous_change_height: self - .previous - .as_ref() - .map(|previous| previous.updated_at_core_height), - }); - } - - fn select_quorums( - &self, - signing_height: u32, - verification_height: u32, - ) -> SelectedVerificationQuorumSets { - let mut quorums = VecDeque::new(); - let mut should_be_verifiable = false; - - if let Some(previous) = &self.previous { - let previous_quorum_height = previous.active_core_height; - let change_quorum_height = previous.updated_at_core_height; - let previous_quorums_change_height = previous.previous_change_height; - - if signing_height > 8 && verification_height >= change_quorum_height { - // in this case we are sure that we should be targeting the current quorum - // We updated core chain lock height from 100 to 105, new chain lock comes in for block 114 - // ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) ------ 106 (new chain lock verification height 114 - 8) - // We are sure that we should use current quorums - // If we have - // ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) ------ 105 (new chain lock verification height 113 - 8) - // We should also use current quorums, this is because at 105 we are sure new chain lock validating quorums are active - quorums.push_back(&self.current_quorums); - should_be_verifiable = true; - } else if signing_height > 8 && verification_height <= previous_quorum_height { - should_be_verifiable = previous_quorums_change_height - .map(|previous_quorums_change_height| { - verification_height > previous_quorums_change_height - }) - .unwrap_or(false); - // In this case the quorums were changed recently meaning that we should use the previous quorums to verify the chain lock - // We updated core chain lock height from 100 to 105, new chain lock comes in for block 106 - // -------- 98 (new chain lock verification height 106 - 8) ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) - // We are sure that we should use previous quorums - // If we have - // -------- 100 (new chain lock verification height 108 - 8) ------- 100 (previous_quorum_height) ------ 105 (change_quorum_height) - // We should also use previous quorums, this is because at 100 we are sure the old quorum set was active - quorums.push_back(&previous.quorums); - } else { - should_be_verifiable = previous_quorums_change_height - .map(|previous_quorums_change_height| { - verification_height > previous_quorums_change_height - }) - .unwrap_or(false); - // we are in between, so we don't actually know if it was the old one or the new one to be used. - // ------- 100 (previous_quorum_height) ------ 104 (new chain lock verification height 112 - 8) -------105 (change_quorum_height) - // we should just try both, starting with the current quorums - quorums.push_back(&self.current_quorums); - quorums.push_back(&previous.quorums); - } - } else { - quorums.push_back(&self.current_quorums); - } - - SelectedVerificationQuorumSets { - quorum_sets: quorums, - should_be_verifiable, - } - } -} diff --git a/packages/rs-drive-abci/src/platform_types/validator_set/mod.rs b/packages/rs-drive-abci/src/platform_types/validator_set/mod.rs index 70fd7fe1067..5dd9adb1f83 100644 --- a/packages/rs-drive-abci/src/platform_types/validator_set/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/validator_set/mod.rs @@ -26,6 +26,12 @@ impl ValidatorSetV0Getters for ValidatorSet { } } + fn quorum_index(&self) -> Option { + match self { + ValidatorSet::V0(v0) => v0.quorum_index(), + } + } + fn core_height(&self) -> u32 { match self { ValidatorSet::V0(v0) => v0.core_height(), @@ -64,6 +70,12 @@ impl ValidatorSetV0Setters for ValidatorSet { } } + fn set_quorum_index(&mut self, index: Option) { + match self { + ValidatorSet::V0(v0) => v0.set_quorum_index(index), + } + } + fn set_core_height(&mut self, core_height: u32) { match self { ValidatorSet::V0(v0) => v0.set_core_height(core_height), diff --git a/packages/rs-drive-abci/src/platform_types/validator_set/v0/mod.rs b/packages/rs-drive-abci/src/platform_types/validator_set/v0/mod.rs index 3adf9559b02..7574a5d31db 100644 --- a/packages/rs-drive-abci/src/platform_types/validator_set/v0/mod.rs +++ b/packages/rs-drive-abci/src/platform_types/validator_set/v0/mod.rs @@ -21,6 +21,8 @@ use tenderdash_abci::proto::{abci, crypto}; pub struct ValidatorSetV0 { /// The quorum hash pub quorum_hash: QuorumHash, + /// Rotation quorum index is available only for DIP24 quorums + pub quorum_index: Option, /// Active height pub core_height: u32, /// The list of masternodes @@ -297,6 +299,7 @@ impl ValidatorSetV0 { let QuorumInfoResult { height, quorum_hash, + quorum_index, quorum_public_key, members, .. @@ -332,8 +335,15 @@ impl ValidatorSetV0 { let threshold_public_key = BlsPublicKey::from_bytes(quorum_public_key.as_slice()) .map_err(ExecutionError::BlsErrorFromDashCoreResponse)?; + let optional_quorum_index = if quorum_index == 0 { + None + } else { + Some(quorum_index) + }; + Ok(ValidatorSetV0 { quorum_hash, + quorum_index: optional_quorum_index, core_height: height, members: validator_set, threshold_public_key, @@ -345,6 +355,8 @@ impl ValidatorSetV0 { pub trait ValidatorSetV0Getters { /// Returns the quorum hash of the validator set. fn quorum_hash(&self) -> &QuorumHash; + /// Returns rotation quorum index. It's available only for DIP24 quorums + fn quorum_index(&self) -> Option; /// Returns the active height of the validator set. fn core_height(&self) -> u32; /// Returns the members of the validator set. @@ -361,6 +373,8 @@ pub trait ValidatorSetV0Getters { pub trait ValidatorSetV0Setters { /// Sets the quorum hash of the validator set. fn set_quorum_hash(&mut self, quorum_hash: QuorumHash); + /// Sets the quorum index of the validator set. + fn set_quorum_index(&mut self, index: Option); /// Sets the active height of the validator set. fn set_core_height(&mut self, core_height: u32); /// Sets the members of the validator set. @@ -374,6 +388,10 @@ impl ValidatorSetV0Getters for ValidatorSetV0 { &self.quorum_hash } + fn quorum_index(&self) -> Option { + self.quorum_index + } + fn core_height(&self) -> u32 { self.core_height } @@ -400,6 +418,10 @@ impl ValidatorSetV0Setters for ValidatorSetV0 { self.quorum_hash = quorum_hash; } + fn set_quorum_index(&mut self, index: Option) { + self.quorum_index = index; + } + fn set_core_height(&mut self, core_height: u32) { self.core_height = core_height; } diff --git a/packages/rs-drive-abci/src/query/response_metadata/v0/mod.rs b/packages/rs-drive-abci/src/query/response_metadata/v0/mod.rs index 12286271562..edd234ab2d4 100644 --- a/packages/rs-drive-abci/src/query/response_metadata/v0/mod.rs +++ b/packages/rs-drive-abci/src/query/response_metadata/v0/mod.rs @@ -28,7 +28,7 @@ impl Platform { Proof { grovedb_proof: proof, quorum_hash: platform_state.last_committed_quorum_hash().to_vec(), - quorum_type: self.config.validator_set_quorum_type() as u32, + quorum_type: self.config.validator_set.quorum_type as u32, block_id_hash: platform_state.last_committed_block_id_hash().to_vec(), signature: platform_state.last_committed_block_signature().to_vec(), round: platform_state.last_committed_block_round(), diff --git a/packages/rs-drive-abci/tests/strategy_tests/chain_lock_update.rs b/packages/rs-drive-abci/tests/strategy_tests/chain_lock_update.rs index f80ec3645de..c406e2159d8 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/chain_lock_update.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/chain_lock_update.rs @@ -4,7 +4,10 @@ mod tests { use crate::execution::run_chain_for_strategy; use crate::strategy::CoreHeightIncrease::RandomCoreHeightIncrease; use crate::strategy::{MasternodeListChangesStrategy, NetworkStrategy}; - use drive_abci::config::{ExecutionConfig, PlatformConfig, PlatformTestConfig}; + use drive_abci::config::{ + ChainLockConfig, ExecutionConfig, InstantLockConfig, PlatformConfig, PlatformTestConfig, + ValidatorSetConfig, + }; use drive_abci::test::helpers::setup::TestPlatformBuilder; use strategy_tests::frequency::Frequency; @@ -58,19 +61,19 @@ mod tests { ..Default::default() }; - let quorum_size = 100; - let config = PlatformConfig { - validator_set_quorum_size: quorum_size, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_400_60".to_string(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, ..Default::default() }, block_spacing_ms: 3000, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let mut platform = TestPlatformBuilder::new() diff --git a/packages/rs-drive-abci/tests/strategy_tests/core_update_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/core_update_tests.rs index 4c892673123..5ec8b6b9d29 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/core_update_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/core_update_tests.rs @@ -4,7 +4,10 @@ mod tests { use crate::execution::run_chain_for_strategy; use crate::strategy::CoreHeightIncrease::RandomCoreHeightIncrease; use crate::strategy::{MasternodeListChangesStrategy, NetworkStrategy}; - use drive_abci::config::{ExecutionConfig, PlatformConfig, PlatformTestConfig}; + use drive_abci::config::{ + ChainLockConfig, ExecutionConfig, InstantLockConfig, PlatformConfig, PlatformTestConfig, + ValidatorSetConfig, + }; use drive_abci::platform_types::platform_state::v0::PlatformStateV0Methods; use drive_abci::platform_types::validator_set::v0::ValidatorSetV0Getters; use drive_abci::test::helpers::setup::TestPlatformBuilder; @@ -61,9 +64,12 @@ mod tests { let quorum_size = 100; let config = PlatformConfig { - validator_set_quorum_size: quorum_size, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_size, + ..Default::default() + }, + + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -159,9 +165,12 @@ mod tests { let quorum_size = 100; let config = PlatformConfig { - validator_set_quorum_size: quorum_size, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_size, + ..Default::default() + }, + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -246,9 +255,12 @@ mod tests { let quorum_size = 100; let config = PlatformConfig { - validator_set_quorum_size: quorum_size, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_size, + ..Default::default() + }, + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, diff --git a/packages/rs-drive-abci/tests/strategy_tests/execution.rs b/packages/rs-drive-abci/tests/strategy_tests/execution.rs index 3db5a245faa..08728958757 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/execution.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/execution.rs @@ -31,6 +31,7 @@ use drive_abci::mimic::{MimicExecuteBlockOptions, MimicExecuteBlockOutcome}; use drive_abci::platform_types::epoch_info::v0::EpochInfoV0; use drive_abci::platform_types::platform::Platform; use drive_abci::platform_types::platform_state::v0::PlatformStateV0Methods; +use drive_abci::platform_types::signature_verification_quorum_set::{Quorums, SigningQuorum}; use drive_abci::platform_types::withdrawal::unsigned_withdrawal_txs::v0::UnsignedWithdrawalTxs; use drive_abci::rpc::core::MockCoreRPCLike; use drive_abci::test::fixture::abci::static_init_chain_request; @@ -50,13 +51,16 @@ pub(crate) fn run_chain_for_strategy( platform: &mut Platform, block_count: u64, strategy: NetworkStrategy, - config: PlatformConfig, + mut config: PlatformConfig, seed: u64, ) -> ChainExecutionOutcome { + // TODO: Do we want to sign instant locks or just disable verification? + let validator_quorum_count = strategy.validator_quorum_count; // In most tests 24 quorums let chain_lock_quorum_count = strategy.chain_lock_quorum_count; // In most tests 4 quorums when not the same as validator - let validator_set_quorum_size = config.validator_set_quorum_size; - let chain_lock_quorum_size = config.chain_lock_quorum_size; + let instant_lock_quorum_count = strategy.instant_lock_quorum_count; // In most tests 24 quorums when not the same as validator + let validator_set_quorum_size = config.validator_set.quorum_size; + let chain_lock_quorum_size = config.chain_lock.quorum_size; let mut rng = StdRng::seed_from_u64(seed); @@ -68,7 +72,7 @@ pub(crate) fn run_chain_for_strategy( let max_core_height = core_height_increase.max_core_height(block_count, strategy.initial_core_height); - let chain_lock_quorum_type = config.chain_lock_quorum_type(); + let chain_lock_quorum_type = config.chain_lock.quorum_type; let sign_chain_locks = strategy.sign_chain_locks; @@ -242,7 +246,7 @@ pub(crate) fn run_chain_for_strategy( &mut rng, ); - let mut quorums_details: Vec<(QuorumHash, ExtendedQuorumDetails)> = validator_quorums + let mut validator_quorums_details: Vec<(QuorumHash, ExtendedQuorumDetails)> = validator_quorums .keys() .map(|quorum_hash| { ( @@ -258,10 +262,10 @@ pub(crate) fn run_chain_for_strategy( }) .collect(); - quorums_details.shuffle(&mut rng); + validator_quorums_details.shuffle(&mut rng); let (chain_lock_quorums, chain_lock_quorums_details) = - if config.validator_set_quorum_type != config.chain_lock_quorum_type { + if config.validator_set.quorum_type != config.chain_lock.quorum_type { let total_chain_lock_quorums = if strategy.rotate_quorums { chain_lock_quorum_count * 10 } else { @@ -301,6 +305,95 @@ pub(crate) fn run_chain_for_strategy( (BTreeMap::new(), vec![]) }; + let (instant_lock_quorum_infos, instant_lock_quorums_details, instant_lock_signing_quorums) = + if config.validator_set.quorum_type != config.instant_lock.quorum_type { + // TODO: Implement instant lock quorums rotation? + let total_instant_lock_quorums = if strategy.rotate_quorums { + instant_lock_quorum_count * 10 + } else { + instant_lock_quorum_count + }; + + let instant_lock_quorums_infos = masternodes::generate_test_quorums( + total_instant_lock_quorums as usize, + initial_all_masternodes + .iter() + .map(|masternode| &masternode.masternode), + config.instant_lock.quorum_size as usize, + &mut rng, + ); + + let mut instant_lock_quorums_details: Vec<(QuorumHash, ExtendedQuorumDetails)> = + instant_lock_quorums_infos + .iter() + .map(|(hash, quorum)| { + ( + *hash, + ExtendedQuorumDetails { + creation_height: 0, + quorum_index: quorum.quorum_index, + mined_block_hash: BlockHash::all_zeros(), + num_valid_members: 0, + health_ratio: 0.0, + }, + ) + }) + .collect(); + + instant_lock_quorums_details.shuffle(&mut rng); + + let instant_lock_signing_quorums: Quorums = + if strategy.sign_instant_locks { + instant_lock_quorums_infos + .iter() + .map(|(quorum_hash, info)| { + let bytes = info.private_key.to_bytes(); + let fixed_bytes: [u8; 32] = bytes + .as_slice() + .try_into() + .expect("Expected a byte array of length 32"); + ( + *quorum_hash, + SigningQuorum { + index: info.quorum_index, + private_key: fixed_bytes, + }, + ) + }) + .collect() + } else { + Default::default() + }; + + ( + instant_lock_quorums_infos, + instant_lock_quorums_details, + instant_lock_signing_quorums, + ) + } else if strategy.sign_instant_locks { + let signing_quorums = validator_quorums + .iter() + .map(|(quorum_hash, info)| { + let bytes = info.private_key.to_bytes(); + let fixed_bytes: [u8; 32] = bytes + .as_slice() + .try_into() + .expect("Expected a byte array of length 32"); + ( + *quorum_hash, + SigningQuorum { + index: info.quorum_index, + private_key: fixed_bytes, + }, + ) + }) + .collect(); + + (Default::default(), Default::default(), signing_quorums) + } else { + Default::default() + }; + let start_core_height = platform.config.abci.genesis_core_height; platform @@ -330,17 +423,12 @@ pub(crate) fn run_chain_for_strategy( })) }); - platform - .core_rpc - .expect_verify_instant_lock() - .returning(|_, _| Ok(true)); - platform .core_rpc .expect_get_quorum_listextended() .returning(move |core_height: Option| { let validator_set_extended_info = if !strategy.rotate_quorums { - quorums_details.clone().into_iter().collect() + validator_quorums_details.clone().into_iter().collect() } else { let core_height = core_height.expect("expected a core height"); // if we rotate quorums we shouldn't give back the same ones every time @@ -350,18 +438,18 @@ pub(crate) fn run_chain_for_strategy( let end_range = end_range % total_validator_quorums as u32; if end_range > start_range { - quorums_details + validator_quorums_details .iter() .skip(start_range as usize) .take((end_range - start_range) as usize) .map(|(quorum_hash, quorum)| (*quorum_hash, quorum.clone())) .collect() } else { - let first_range = quorums_details + let first_range = validator_quorums_details .iter() .skip(start_range as usize) .take((total_validator_quorums as u32 - start_range) as usize); - let second_range = quorums_details.iter().take(end_range as usize); + let second_range = validator_quorums_details.iter().take(end_range as usize); first_range .chain(second_range) .map(|(quorum_hash, quorum)| (*quorum_hash, quorum.clone())) @@ -379,6 +467,13 @@ pub(crate) fn run_chain_for_strategy( ); } + if !instant_lock_quorums_details.is_empty() { + quorums_by_type.insert( + QuorumType::Llmq60_75, + instant_lock_quorums_details.clone().into_iter().collect(), + ); + } + let result = ExtendedQuorumListResult { quorums_by_type }; Ok(result) @@ -387,6 +482,7 @@ pub(crate) fn run_chain_for_strategy( let all_quorums_info: HashMap = validator_quorums .iter() .chain(chain_lock_quorums.iter()) + .chain(instant_lock_quorum_infos.iter()) .map(|(quorum_hash, test_quorum_info)| (*quorum_hash, test_quorum_info.into())) .collect(); @@ -661,6 +757,7 @@ pub(crate) fn run_chain_for_strategy( block_count, all_hpmns_with_updates, validator_quorums, + instant_lock_signing_quorums, strategy, config, rng, @@ -671,7 +768,8 @@ pub(crate) fn create_chain_for_strategy( platform: &Platform, block_count: u64, proposers_with_updates: Vec, - quorums: BTreeMap, + validator_quorums: BTreeMap, + instant_lock_quorums: Quorums, strategy: NetworkStrategy, config: PlatformConfig, rng: StdRng, @@ -688,7 +786,8 @@ pub(crate) fn create_chain_for_strategy( abci_application, block_count, proposers_with_updates, - quorums, + validator_quorums, + instant_lock_quorums, strategy, config, seed, @@ -699,7 +798,8 @@ pub(crate) fn start_chain_for_strategy( abci_application: FullAbciApplication, block_count: u64, proposers_with_updates: Vec, - quorums: BTreeMap, + validator_quorums: BTreeMap, + instant_lock_quorums: Quorums, strategy: NetworkStrategy, config: PlatformConfig, seed: StrategyRandomness, @@ -709,14 +809,14 @@ pub(crate) fn start_chain_for_strategy( StrategyRandomness::RNGEntropy(rng) => rng, }; - let quorum_hashes: Vec<&QuorumHash> = quorums.keys().collect(); + let quorum_hashes: Vec<&QuorumHash> = validator_quorums.keys().collect(); - let mut current_quorum_hash = **quorum_hashes + let mut current_validator_quorum_hash = **quorum_hashes .choose(&mut rng) .expect("expected quorums to be initialized"); - let current_quorum_with_test_info = quorums - .get::(¤t_quorum_hash) + let current_quorum_with_test_info = validator_quorums + .get::(¤t_validator_quorum_hash) .expect("expected a quorum to be found"); // init chain @@ -743,7 +843,7 @@ pub(crate) fn start_chain_for_strategy( current_quorum_with_test_info.public_key.to_bytes().to_vec(), )), }), - quorum_hash: current_quorum_hash.to_byte_array().to_vec(), + quorum_hash: current_validator_quorum_hash.to_byte_array().to_vec(), }); let ResponseInitChain { @@ -754,7 +854,7 @@ pub(crate) fn start_chain_for_strategy( .expect("should init chain"); // initialization will change the current quorum hash - current_quorum_hash = abci_application + current_validator_quorum_hash = abci_application .platform .state .load() @@ -767,8 +867,9 @@ pub(crate) fn start_chain_for_strategy( core_height_start: initial_core_height, block_count, proposers: proposers_with_updates, - quorums, - current_quorum_hash, + validator_quorums, + current_validator_quorum_hash, + instant_lock_quorums, current_proposer_versions: None, current_identity_nonce_counter: Default::default(), current_identity_contract_nonce_counter: Default::default(), @@ -794,19 +895,20 @@ pub(crate) fn continue_chain_for_strategy( core_height_start: _, block_count, proposers: proposers_with_updates, - quorums, - mut current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: mut current_quorum_hash, current_proposer_versions, mut current_identity_nonce_counter, mut current_identity_contract_nonce_counter, start_time_ms, mut current_time_ms, + instant_lock_quorums, } = chain_execution_parameters; let mut rng = match seed { StrategyRandomness::SeedEntropy(seed) => StdRng::seed_from_u64(seed), StrategyRandomness::RNGEntropy(rng) => rng, }; - let quorum_size = config.validator_set_quorum_size; + let quorum_size = config.validator_set.quorum_size; let first_block_time = start_time_ms; let mut current_identities = vec![]; let mut signer = strategy.strategy.signer.clone().unwrap_or_default(); @@ -877,6 +979,7 @@ pub(crate) fn continue_chain_for_strategy( &mut current_identity_contract_nonce_counter, &mut signer, &mut rng, + &instant_lock_quorums, ); state_transitions_per_block.insert(block_height, state_transitions.clone()); @@ -1013,7 +1116,7 @@ pub(crate) fn continue_chain_for_strategy( query_strategy.query_chain_for_strategy( &ProofVerification { quorum_hash: ¤t_quorum_with_test_info.quorum_hash.into(), - quorum_type: config.validator_set_quorum_type(), + quorum_type: config.validator_set.quorum_type, app_version, chain_id: drive_abci::mimic::CHAIN_ID.to_string(), core_chain_locked_height: state_id.core_chain_locked_height, @@ -1076,8 +1179,8 @@ pub(crate) fn continue_chain_for_strategy( masternode_identity_balances, identities: current_identities, proposers: proposers_with_updates, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: proposer_versions, identity_nonce_counter: current_identity_nonce_counter, identity_contract_nonce_counter: current_identity_contract_nonce_counter, @@ -1087,5 +1190,6 @@ pub(crate) fn continue_chain_for_strategy( withdrawals: total_withdrawals, validator_set_updates, state_transition_results_per_block, + instant_lock_quorums, } } diff --git a/packages/rs-drive-abci/tests/strategy_tests/failures.rs b/packages/rs-drive-abci/tests/strategy_tests/failures.rs index c1fe8150951..addb94cdbf7 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/failures.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/failures.rs @@ -7,7 +7,10 @@ mod tests { use crate::strategy::{FailureStrategy, NetworkStrategy}; use strategy_tests::{IdentityInsertInfo, StartIdentities, Strategy}; - use drive_abci::config::{ExecutionConfig, PlatformConfig, PlatformTestConfig}; + use drive_abci::config::{ + ChainLockConfig, ExecutionConfig, InstantLockConfig, PlatformConfig, PlatformTestConfig, + ValidatorSetConfig, + }; use dpp::dashcore::hashes::Hash; use dpp::dashcore::{BlockHash, ChainLock}; @@ -75,16 +78,20 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, ..Default::default() }, block_spacing_ms: 3000, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let mut platform = TestPlatformBuilder::new() @@ -150,9 +157,9 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -198,9 +205,9 @@ mod tests { // // We use the dpns contract and we insert two documents both with the same "name" // // This is a common scenario we should see quite often // let config = PlatformConfig { - // validator_set_quorum_size: 100, - // validator_set_quorum_type: "llmq_100_67".to_string(), - // chain_lock_quorum_type: "llmq_100_67".to_string(), + // validator_set_quorum_quorum_size: 100, + // validator_set_quorum_type: QuorumType::Llmq100_67, + // chain_lock_quorum_type: QuorumType::Llmq100_67, // execution: ExecutionConfig { // //we disable document triggers because we are using dpns and dpns needs a preorder // use_document_triggers: false, diff --git a/packages/rs-drive-abci/tests/strategy_tests/main.rs b/packages/rs-drive-abci/tests/strategy_tests/main.rs index 43ea171e360..bef89ceca8c 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/main.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/main.rs @@ -47,7 +47,7 @@ mod tests { use dashcore_rpc::dashcore::hashes::Hash; use dashcore_rpc::dashcore::BlockHash; use dashcore_rpc::dashcore_rpc_json::AssetUnlockStatus; - use dashcore_rpc::json::AssetUnlockStatusResult; + use dashcore_rpc::json::{AssetUnlockStatusResult, QuorumType}; use dpp::block::extended_block_info::v0::ExtendedBlockInfoV0Getters; use std::sync::{Arc, Mutex}; use strategy_tests::operations::DocumentAction::{ @@ -74,7 +74,9 @@ mod tests { use dpp::version::PlatformVersion; use drive::drive::config::DEFAULT_QUERY_LIMIT; use drive::drive::identity::withdrawals::WithdrawalTransactionIndex; - use drive_abci::config::{ExecutionConfig, PlatformTestConfig}; + use drive_abci::config::{ + ChainLockConfig, ExecutionConfig, InstantLockConfig, PlatformTestConfig, ValidatorSetConfig, + }; use drive_abci::logging::LogLevel; use drive_abci::platform_types::platform_state::v0::PlatformStateV0Methods; @@ -113,9 +115,9 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -158,9 +160,9 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -203,9 +205,9 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -225,12 +227,13 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = run_chain_for_strategy(&mut platform, 15, strategy.clone(), config.clone(), 40); @@ -289,13 +292,14 @@ mod tests { core_height_start: 1, block_count: 30, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: 1681094380000, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy, config, @@ -335,9 +339,9 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -357,12 +361,13 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = run_chain_for_strategy(&mut platform, 15, strategy.clone(), config.clone(), 40); @@ -421,13 +426,14 @@ mod tests { core_height_start: 1, block_count: 30, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: 1681094380000, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy, config, @@ -468,16 +474,20 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, ..Default::default() }, block_spacing_ms: 3000, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let mut platform = TestPlatformBuilder::new() @@ -530,9 +540,9 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -579,9 +589,9 @@ mod tests { }; let hour_in_ms = 1000 * 60 * 60; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, @@ -636,9 +646,9 @@ mod tests { let hour_in_s = 60 * 60; let three_mins_in_ms = 1000 * 60 * 3; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, @@ -694,9 +704,25 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 10, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 10, + ..Default::default() + }, + chain_lock: ChainLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 10, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, + instant_lock: InstantLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 10, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -774,9 +800,25 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 10, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 10, + ..Default::default() + }, + chain_lock: ChainLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 10, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, + instant_lock: InstantLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 10, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -841,9 +883,25 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 10, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 10, + ..Default::default() + }, + chain_lock: ChainLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 10, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, + instant_lock: InstantLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 10, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -903,9 +961,25 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 10, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 10, + ..Default::default() + }, + chain_lock: ChainLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 10, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, + instant_lock: InstantLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 10, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -962,7 +1036,8 @@ mod tests { #[test] fn run_chain_insert_one_new_identity_per_block_with_block_signing() { - // drive_abci::logging::Loggers::default().try_install().ok(); + drive_abci::logging::init_for_tests(LogLevel::Silent); + let strategy = NetworkStrategy { strategy: Strategy { start_contracts: vec![], @@ -995,12 +1070,13 @@ mod tests { }, }), verify_state_transition_results: true, + sign_instant_locks: true, ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -1052,16 +1128,20 @@ mod tests { }; let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, ..Default::default() }, block_spacing_ms: day_in_ms, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; @@ -1133,16 +1213,20 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, ..Default::default() }, block_spacing_ms: 3000, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let mut platform = TestPlatformBuilder::new() @@ -1252,9 +1336,9 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -1339,16 +1423,20 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, ..Default::default() }, block_spacing_ms: 3000, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let mut platform = TestPlatformBuilder::new() @@ -1443,9 +1531,9 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -1524,16 +1612,20 @@ mod tests { }; let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, ..Default::default() }, block_spacing_ms: day_in_ms, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let block_count = 120; @@ -1632,16 +1724,20 @@ mod tests { }; let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, ..Default::default() }, block_spacing_ms: day_in_ms, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let block_count = 120; @@ -1740,16 +1836,20 @@ mod tests { }; let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, ..Default::default() }, block_spacing_ms: day_in_ms, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; @@ -1866,16 +1966,20 @@ mod tests { }; let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, ..Default::default() }, block_spacing_ms: day_in_ms, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; @@ -1991,9 +2095,9 @@ mod tests { }; let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, @@ -2105,9 +2209,9 @@ mod tests { }; let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, @@ -2219,9 +2323,9 @@ mod tests { let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, @@ -2229,7 +2333,11 @@ mod tests { ..Default::default() }, block_spacing_ms: day_in_ms, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let block_count = 30; @@ -2348,9 +2456,9 @@ mod tests { let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, @@ -2358,7 +2466,11 @@ mod tests { ..Default::default() }, block_spacing_ms: day_in_ms, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let block_count = 30; @@ -2493,9 +2605,9 @@ mod tests { let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, @@ -2503,7 +2615,11 @@ mod tests { ..Default::default() }, block_spacing_ms: day_in_ms, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let block_count = 30; @@ -2559,12 +2675,13 @@ mod tests { failure_testing: None, query_testing: None, verify_state_transition_results: true, + sign_instant_locks: true, ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, @@ -2642,16 +2759,20 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, ..Default::default() }, block_spacing_ms: 3000, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let mut platform = TestPlatformBuilder::new() @@ -2727,16 +2848,20 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, ..Default::default() }, block_spacing_ms: 3000, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let mut platform = TestPlatformBuilder::new() @@ -2824,16 +2949,20 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, ..Default::default() }, block_spacing_ms: 3000, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; @@ -2901,12 +3030,13 @@ mod tests { ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. }, last_block_pooled_withdrawals_amount, @@ -2940,13 +3070,14 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, withdrawals: last_block_withdrawals, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = { let outcome = continue_chain_for_strategy( @@ -2956,13 +3087,14 @@ mod tests { core_height_start: 1, block_count: 1, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: GENESIS_TIME_MS, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy.clone(), config.clone(), @@ -3019,13 +3151,14 @@ mod tests { ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, withdrawals: last_block_withdrawals, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. }, last_block_broadcased_withdrawals_amount, @@ -3037,13 +3170,14 @@ mod tests { core_height_start: 1, block_count: 1, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: GENESIS_TIME_MS, current_time_ms: end_time_ms + 1000, + instant_lock_quorums, }, strategy.clone(), config.clone(), @@ -3131,13 +3265,14 @@ mod tests { ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, withdrawals: last_block_withdrawals, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. }, last_block_withdrawals_completed_amount, @@ -3149,13 +3284,14 @@ mod tests { core_height_start: 1, block_count: 1, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: GENESIS_TIME_MS, current_time_ms: end_time_ms + 1000, + instant_lock_quorums, }, strategy.clone(), config.clone(), @@ -3256,13 +3392,14 @@ mod tests { core_height_start: 1, block_count: 1, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: GENESIS_TIME_MS, current_time_ms: end_time_ms + 1000, + instant_lock_quorums, }, strategy.clone(), config.clone(), @@ -3387,9 +3524,25 @@ mod tests { }; let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 3, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 3, + ..Default::default() + }, + chain_lock: ChainLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 3, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, + instant_lock: InstantLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 3, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 1, @@ -3552,9 +3705,25 @@ mod tests { }; let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 3, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 3, + ..Default::default() + }, + chain_lock: ChainLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 3, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, + instant_lock: InstantLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 3, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 1, @@ -3688,16 +3857,36 @@ mod tests { }; let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 3, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 3, + ..Default::default() + }, + chain_lock: ChainLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 3, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, + instant_lock: InstantLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 3, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 1, ..Default::default() }, block_spacing_ms: day_in_ms, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let mut platform_a = TestPlatformBuilder::new() @@ -3814,9 +4003,25 @@ mod tests { }; let day_in_ms = 1000 * 60 * 60 * 24; let config = PlatformConfig { - validator_set_quorum_size: 3, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 3, + ..Default::default() + }, + chain_lock: ChainLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 3, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, + instant_lock: InstantLockConfig { + quorum_type: QuorumType::Llmq100_67, + quorum_size: 3, + quorum_window: 24, + quorum_active_signers: 24, + quorum_rotation: false, + }, execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 1, @@ -3837,8 +4042,8 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, identity_nonce_counter, @@ -3899,8 +4104,9 @@ mod tests { core_height_start: 10, block_count: 30, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, + instant_lock_quorums: Default::default(), current_proposer_versions: Some(current_proposer_versions), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, @@ -3958,16 +4164,20 @@ mod tests { }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, ..Default::default() }, block_spacing_ms: 3000, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; @@ -4014,16 +4224,20 @@ mod tests { ..Default::default() }; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 25, ..Default::default() }, block_spacing_ms: 3000, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; let mut platform = TestPlatformBuilder::new() diff --git a/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs b/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs index d240752a265..7dcde2d97af 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/masternodes.rs @@ -537,6 +537,7 @@ where TestQuorumInfo::from_quorum_hash_and_pro_tx_hashes( index as u32 * 24, quorum_hash, + Some(index as u32 + 1), validator_pro_tx_hashes, rng, ), diff --git a/packages/rs-drive-abci/tests/strategy_tests/query.rs b/packages/rs-drive-abci/tests/strategy_tests/query.rs index c8825c7dfef..e7e4fd7ca9e 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/query.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/query.rs @@ -306,7 +306,10 @@ mod tests { use dpp::block::extended_epoch_info::v0::ExtendedEpochInfoV0Getters; use dpp::version::PlatformVersion; - use drive_abci::config::{ExecutionConfig, PlatformConfig, PlatformTestConfig}; + use drive_abci::config::{ + ChainLockConfig, ExecutionConfig, InstantLockConfig, PlatformConfig, PlatformTestConfig, + ValidatorSetConfig, + }; use drive_abci::platform_types::platform_state::v0::PlatformStateV0Methods; use drive_abci::test::helpers::setup::TestPlatformBuilder; @@ -369,9 +372,9 @@ mod tests { }; let hour_in_ms = 1000 * 60 * 60; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, @@ -467,9 +470,9 @@ mod tests { }; let hour_in_ms = 1000 * 60 * 60; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, @@ -566,9 +569,9 @@ mod tests { }; let hour_in_ms = 1000 * 60 * 60; let config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 100, diff --git a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs index dae0d7acc8f..43fba42224d 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/strategy.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/strategy.rs @@ -40,7 +40,7 @@ use drive_abci::rpc::core::MockCoreRPCLike; use rand::prelude::{IteratorRandom, SliceRandom, StdRng}; use rand::Rng; use strategy_tests::{KeyMaps, Strategy}; -use strategy_tests::transitions::{create_state_transitions_for_identities, instant_asset_lock_proof_fixture}; +use strategy_tests::transitions::{create_state_transitions_for_identities, create_state_transitions_for_identities_and_proofs, instant_asset_lock_proof_fixture}; use std::borrow::Cow; use std::collections::{BTreeMap, HashMap, HashSet}; use std::str::FromStr; @@ -48,8 +48,9 @@ use tenderdash_abci::proto::abci::{ExecTxResult, ValidatorSetUpdate}; use dpp::data_contract::document_type::accessors::DocumentTypeV0Getters; use dpp::data_contract::document_type::v0::DocumentTypeV0; use dpp::identity::accessors::IdentityGettersV0; +use dpp::identity::state_transition::asset_lock_proof::InstantAssetLockProof; use dpp::platform_value::{BinaryData, Value}; -use dpp::prelude::{Identifier, IdentityNonce}; +use dpp::prelude::{AssetLockProof, Identifier, IdentityNonce}; use dpp::state_transition::documents_batch_transition::document_base_transition::v0::DocumentBaseTransitionV0; use dpp::state_transition::documents_batch_transition::document_create_transition::{DocumentCreateTransition, DocumentCreateTransitionV0}; use dpp::state_transition::documents_batch_transition::document_transition::document_delete_transition::DocumentDeleteTransitionV0; @@ -59,7 +60,10 @@ use dpp::state_transition::documents_batch_transition::document_transition::{Doc use drive::drive::document::query::QueryDocumentsOutcomeV0Methods; use dpp::state_transition::data_contract_create_transition::methods::v0::DataContractCreateTransitionMethodsV0; use dpp::state_transition::documents_batch_transition::document_transition::document_transfer_transition::DocumentTransferTransitionV0; +use dpp::state_transition::identity_topup_transition::v0::IdentityTopUpTransitionV0; use drive_abci::abci::app::FullAbciApplication; +use drive_abci::config::PlatformConfig; +use drive_abci::platform_types::signature_verification_quorum_set::{QuorumConfig, Quorums, SigningQuorum}; use drive_abci::platform_types::withdrawal::unsigned_withdrawal_txs::v0::UnsignedWithdrawalTxs; use crate::strategy::CoreHeightIncrease::NoCoreHeightIncrease; @@ -240,6 +244,7 @@ pub struct NetworkStrategy { pub extra_normal_mns: u16, pub validator_quorum_count: u16, pub chain_lock_quorum_count: u16, + pub instant_lock_quorum_count: u16, pub initial_core_height: u32, pub upgrading_info: Option, pub core_height_increase: CoreHeightIncrease, @@ -251,6 +256,7 @@ pub struct NetworkStrategy { pub max_tx_bytes_per_block: u64, pub independent_process_proposal_verification: bool, pub sign_chain_locks: bool, + pub sign_instant_locks: bool, } impl Default for NetworkStrategy { @@ -261,6 +267,7 @@ impl Default for NetworkStrategy { extra_normal_mns: 0, validator_quorum_count: 24, chain_lock_quorum_count: 24, + instant_lock_quorum_count: 24, initial_core_height: 1, upgrading_info: None, core_height_increase: NoCoreHeightIncrease, @@ -272,6 +279,7 @@ impl Default for NetworkStrategy { max_tx_bytes_per_block: 44800, independent_process_proposal_verification: false, sign_chain_locks: false, + sign_instant_locks: false, } } } @@ -365,16 +373,18 @@ impl NetworkStrategy { block_info: &BlockInfo, signer: &mut SimpleSigner, rng: &mut StdRng, + instant_lock_quorums: &Quorums, + platform_config: &PlatformConfig, platform_version: &PlatformVersion, ) -> Result, ProtocolError> { let mut state_transitions = vec![]; if block_info.height == 1 && self.strategy.start_identities.number_of_identities > 0 { - let mut new_transitions = NetworkStrategy::create_identities_state_transitions( + let mut new_transitions = self.create_identities_state_transitions( self.strategy.start_identities.number_of_identities.into(), - self.strategy.identity_inserts.start_keys as KeyID, - &self.strategy.identity_inserts.extra_keys, signer, rng, + instant_lock_quorums, + platform_config, platform_version, ); state_transitions.append(&mut new_transitions); @@ -382,12 +392,12 @@ impl NetworkStrategy { let frequency = &self.strategy.identity_inserts.frequency; if frequency.check_hit(rng) { let count = frequency.events(rng); - let mut new_transitions = NetworkStrategy::create_identities_state_transitions( + let mut new_transitions = self.create_identities_state_transitions( count, - self.strategy.identity_inserts.start_keys as KeyID, - &self.strategy.identity_inserts.extra_keys, signer, rng, + instant_lock_quorums, + platform_config, platform_version, ); state_transitions.append(&mut new_transitions); @@ -522,6 +532,7 @@ impl NetworkStrategy { signer: &mut SimpleSigner, identity_nonce_counter: &mut BTreeMap, contract_nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, + instant_lock_quorums: &Quorums, rng: &mut StdRng, platform_version: &PlatformVersion, ) -> (Vec, Vec) { @@ -1046,9 +1057,11 @@ impl NetworkStrategy { .collect(); for random_identity in random_identities { - operations.push(NetworkStrategy::create_identity_top_up_transition( + operations.push(self.create_identity_top_up_transition( rng, random_identity, + instant_lock_quorums, + &platform.config, platform_version, )); } @@ -1252,6 +1265,7 @@ impl NetworkStrategy { contract_nonce_counter: &mut BTreeMap<(Identifier, Identifier), u64>, signer: &mut SimpleSigner, rng: &mut StdRng, + instant_lock_quorums: &Quorums, ) -> (Vec, Vec) { let mut finalize_block_operations = vec![]; let platform_state = platform.state.load(); @@ -1259,8 +1273,14 @@ impl NetworkStrategy { .current_platform_version() .expect("expected platform version"); - let identity_state_transitions_result = - self.identity_state_transitions_for_block(block_info, signer, rng, platform_version); + let identity_state_transitions_result = self.identity_state_transitions_for_block( + block_info, + signer, + rng, + instant_lock_quorums, + &platform.config, + platform_version, + ); // Handle the Result returned by identity_state_transitions_for_block let (mut identities, mut state_transitions) = match identity_state_transitions_result { @@ -1293,6 +1313,7 @@ impl NetworkStrategy { signer, identity_nonce_counter, contract_nonce_counter, + instant_lock_quorums, rng, platform_version, ); @@ -1317,13 +1338,17 @@ impl NetworkStrategy { // add this because strategy tests library now requires a callback and uses the actual chain. fn create_identities_state_transitions( + &self, count: u16, - key_count: KeyID, - extra_keys: &KeyMaps, signer: &mut SimpleSigner, rng: &mut StdRng, + instant_lock_quorums: &Quorums, + platform_config: &PlatformConfig, platform_version: &PlatformVersion, ) -> Vec<(Identity, StateTransition)> { + let key_count = self.strategy.identity_inserts.start_keys as KeyID; + let extra_keys = &self.strategy.identity_inserts.extra_keys; + let (mut identities, mut keys) = Identity::random_identities_with_private_keys_with_rng::< Vec<_>, >(count, key_count, rng, platform_version) @@ -1352,13 +1377,33 @@ impl NetworkStrategy { } signer.add_keys(keys); - create_state_transitions_for_identities(identities, signer, rng, platform_version) + + if self.sign_instant_locks { + let identities_with_proofs = create_signed_instant_asset_lock_proofs_for_identities( + identities, + rng, + instant_lock_quorums, + platform_config, + platform_version, + ); + + create_state_transitions_for_identities_and_proofs( + identities_with_proofs, + signer, + platform_version, + ) + } else { + create_state_transitions_for_identities(identities, signer, rng, platform_version) + } } // add this because strategy tests library now requires a callback and uses the actual chain. fn create_identity_top_up_transition( + &self, rng: &mut StdRng, identity: &Identity, + instant_lock_quorums: &Quorums, + platform_config: &PlatformConfig, platform_version: &PlatformVersion, ) -> StateTransition { let (_, pk) = ECDSA_SECP256K1 @@ -1366,9 +1411,43 @@ impl NetworkStrategy { .unwrap(); let sk: [u8; 32] = pk.try_into().unwrap(); let secret_key = SecretKey::from_str(hex::encode(sk).as_str()).unwrap(); - let asset_lock_proof = + let mut asset_lock_proof = instant_asset_lock_proof_fixture(PrivateKey::new(secret_key, Network::Dash)); + // Sign transaction and update signature in instant lock proof + if self.sign_instant_locks { + let quorum_config = QuorumConfig { + quorum_type: platform_config.instant_lock.quorum_type, + active_signers: platform_config.instant_lock.quorum_active_signers, + rotation: platform_config.instant_lock.quorum_rotation, + window: platform_config.instant_lock.quorum_window, + }; + + // Sign transaction and update instant lock + let AssetLockProof::Instant(InstantAssetLockProof { instant_lock, .. }) = + &mut asset_lock_proof + else { + panic!("must be instant lock proof"); + }; + + let request_id = instant_lock + .request_id() + .expect("failed to build request id"); + + let (quorum_hash, quorum) = instant_lock_quorums + .choose_quorum(&quorum_config, request_id.as_ref()) + .expect("failed to choose quorum for instant lock transaction signing"); + + instant_lock.signature = quorum + .sign_for_instant_lock( + &quorum_config, + &quorum_hash, + request_id.as_ref(), + &instant_lock.txid, + ) + .expect("failed to sign transaction for instant lock"); + } + IdentityTopUpTransition::try_from_identity( identity, asset_lock_proof, @@ -1399,9 +1478,10 @@ pub struct ChainExecutionOutcome<'a> { pub masternode_identity_balances: BTreeMap<[u8; 32], Credits>, pub identities: Vec, pub proposers: Vec, - pub quorums: BTreeMap, - pub current_quorum_hash: QuorumHash, + pub validator_quorums: BTreeMap, + pub current_validator_quorum_hash: QuorumHash, pub current_proposer_versions: Option>, + pub instant_lock_quorums: Quorums, /// Identity nonce counters pub identity_nonce_counter: BTreeMap, /// Identity Contract nonce counters @@ -1417,8 +1497,8 @@ pub struct ChainExecutionOutcome<'a> { impl<'a> ChainExecutionOutcome<'a> { pub fn current_quorum(&self) -> &TestQuorumInfo { - self.quorums - .get::(&self.current_quorum_hash) + self.validator_quorums + .get::(&self.current_validator_quorum_hash) .unwrap() } } @@ -1428,8 +1508,9 @@ pub struct ChainExecutionParameters { pub core_height_start: u32, pub block_count: u64, pub proposers: Vec, - pub quorums: BTreeMap, - pub current_quorum_hash: QuorumHash, + pub validator_quorums: BTreeMap, + pub current_validator_quorum_hash: QuorumHash, + pub instant_lock_quorums: Quorums, // the first option is if it is set // the second option is if we are even upgrading pub current_proposer_versions: Option>>, @@ -1438,3 +1519,60 @@ pub struct ChainExecutionParameters { pub start_time_ms: u64, pub current_time_ms: u64, } + +fn create_signed_instant_asset_lock_proofs_for_identities( + identities: Vec, + rng: &mut StdRng, + instant_lock_quorums: &Quorums, + platform_config: &PlatformConfig, + platform_version: &PlatformVersion, +) -> Vec<(Identity, [u8; 32], AssetLockProof)> { + let quorum_config = QuorumConfig { + quorum_type: platform_config.instant_lock.quorum_type, + active_signers: platform_config.instant_lock.quorum_active_signers, + rotation: platform_config.instant_lock.quorum_rotation, + window: platform_config.instant_lock.quorum_window, + }; + + identities + .into_iter() + .map(|identity| { + // Create instant asset lock proof + let (_, pk) = ECDSA_SECP256K1 + .random_public_and_private_key_data(rng, platform_version) + .unwrap(); + + let pk_fixed: [u8; 32] = pk.try_into().unwrap(); + let secret_key = SecretKey::from_str(hex::encode(pk_fixed).as_str()).unwrap(); + let private_key = PrivateKey::new(secret_key, Network::Dash); + + let mut asset_lock_proof = instant_asset_lock_proof_fixture(private_key); + + // Sign transaction and update instant lock + let AssetLockProof::Instant(InstantAssetLockProof { instant_lock, .. }) = + &mut asset_lock_proof + else { + panic!("must be instant lock proof"); + }; + + let request_id = instant_lock + .request_id() + .expect("failed to build request id"); + + let (quorum_hash, quorum) = instant_lock_quorums + .choose_quorum(&quorum_config, request_id.as_ref()) + .expect("failed to choose quorum for instant lock transaction signing"); + + instant_lock.signature = quorum + .sign_for_instant_lock( + &quorum_config, + &quorum_hash, + request_id.as_ref(), + &instant_lock.txid, + ) + .expect("failed to sign transaction for instant lock"); + + (identity, pk_fixed, asset_lock_proof) + }) + .collect() +} diff --git a/packages/rs-drive-abci/tests/strategy_tests/upgrade_fork_tests.rs b/packages/rs-drive-abci/tests/strategy_tests/upgrade_fork_tests.rs index 7b588734515..0146fc16f7d 100644 --- a/packages/rs-drive-abci/tests/strategy_tests/upgrade_fork_tests.rs +++ b/packages/rs-drive-abci/tests/strategy_tests/upgrade_fork_tests.rs @@ -13,7 +13,10 @@ mod tests { ChainExecutionOutcome, ChainExecutionParameters, CoreHeightIncrease, MasternodeListChangesStrategy, NetworkStrategy, StrategyRandomness, UpgradingInfo, }; - use drive_abci::config::{ExecutionConfig, PlatformConfig, PlatformTestConfig}; + use drive_abci::config::{ + ChainLockConfig, ExecutionConfig, InstantLockConfig, PlatformConfig, PlatformTestConfig, + ValidatorSetConfig, + }; use drive_abci::mimic::MimicExecuteBlockOptions; use drive_abci::platform_types::platform_state::v0::PlatformStateV0Methods; use drive_abci::test::helpers::setup::TestPlatformBuilder; @@ -64,9 +67,9 @@ mod tests { }; let twenty_minutes_in_ms = 1000 * 60 * 20; let mut config = PlatformConfig { - validator_set_quorum_size: 100, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig::default_100_67(), + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 125, @@ -98,12 +101,13 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = run_chain_for_strategy( &mut platform, @@ -162,11 +166,12 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = continue_chain_for_strategy( abci_app, @@ -175,13 +180,14 @@ mod tests { core_height_start: 1, block_count: 200, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions.clone()), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: 1681094380000, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy.clone(), config.clone(), @@ -225,13 +231,14 @@ mod tests { core_height_start: 1, block_count: 400, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: 1681094380000, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy, config, @@ -307,9 +314,12 @@ mod tests { let one_hour_in_s = 60 * 60; let thirty_seconds_in_ms = 1000 * 30; let config = PlatformConfig { - validator_set_quorum_size: 30, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_size: 30, + ..Default::default() + }, + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 30, @@ -337,12 +347,13 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = run_chain_for_strategy( &mut platform, @@ -398,11 +409,12 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = continue_chain_for_strategy( abci_app, @@ -411,13 +423,14 @@ mod tests { core_height_start: 1, block_count: 1, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions.clone()), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: 1681094380000, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy.clone(), config.clone(), @@ -461,13 +474,14 @@ mod tests { core_height_start: 1, block_count: 120, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: 1681094380000, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy, config, @@ -544,14 +558,23 @@ mod tests { let epoch_time_length_s = 60; let config = PlatformConfig { - validator_set_quorum_size: 30, + validator_set: ValidatorSetConfig { + quorum_size: 30, + ..Default::default() + }, + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { epoch_time_length_s, ..Default::default() }, initial_protocol_version: TEST_PROTOCOL_VERSION_4_WITH_1_HPMN_UPGRADE, block_spacing_ms: epoch_time_length_s * 1000, - testing_configs: PlatformTestConfig::default_with_no_block_signing(), + testing_configs: PlatformTestConfig { + block_signing: false, + block_commit_signature_verification: false, + disable_instant_lock_signature_verification: true, + }, ..Default::default() }; @@ -562,8 +585,8 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, end_time_ms, .. } = run_chain_for_strategy(&mut platform, 1, strategy.clone(), config.clone(), 13); @@ -701,9 +724,12 @@ mod tests { }; let hour_in_ms = 1000 * 60 * 60; let config = PlatformConfig { - validator_set_quorum_size: 40, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_size: 40, + ..Default::default() + }, + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 80, @@ -736,12 +762,13 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = run_chain_for_strategy( &mut platform, @@ -789,12 +816,13 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = continue_chain_for_strategy( abci_app, @@ -803,13 +831,14 @@ mod tests { core_height_start: 1, block_count: 2500, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions.clone()), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: 1681094380000, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy.clone(), config.clone(), @@ -856,13 +885,14 @@ mod tests { core_height_start: 1, block_count: 400, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: 1681094380000, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy, config, @@ -934,9 +964,12 @@ mod tests { }; let hour_in_ms = 1000 * 60 * 60; let mut config = PlatformConfig { - validator_set_quorum_size: 50, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_size: 50, + ..Default::default() + }, + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 50, @@ -968,12 +1001,13 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = run_chain_for_strategy( &mut platform, @@ -1013,12 +1047,13 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = continue_chain_for_strategy( abci_app, @@ -1027,13 +1062,14 @@ mod tests { core_height_start: 1, block_count: 3000, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: 1681094380000, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy, config.clone(), @@ -1108,13 +1144,14 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = continue_chain_for_strategy( abci_app, @@ -1123,13 +1160,14 @@ mod tests { core_height_start: 1, block_count: 2000, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: None, //restart the proposer versions current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: 1681094380000, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy.clone(), config.clone(), @@ -1178,13 +1216,14 @@ mod tests { core_height_start: 1, block_count: 100, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: Some(current_proposer_versions), current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: 1681094380000, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy, config, @@ -1263,9 +1302,12 @@ mod tests { }; let hour_in_ms = 1000 * 60 * 60; let config = PlatformConfig { - validator_set_quorum_size: 50, - validator_set_quorum_type: "llmq_100_67".to_string(), - chain_lock_quorum_type: "llmq_100_67".to_string(), + validator_set: ValidatorSetConfig { + quorum_size: 50, + ..Default::default() + }, + chain_lock: ChainLockConfig::default_100_67(), + instant_lock: InstantLockConfig::default_100_67(), execution: ExecutionConfig { verify_sum_trees: true, validator_set_rotation_block_count: 30, @@ -1297,11 +1339,12 @@ mod tests { let ChainExecutionOutcome { abci_app, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, end_time_ms, identity_nonce_counter, identity_contract_nonce_counter, + instant_lock_quorums, .. } = run_chain_for_strategy(&mut platform, 1400, strategy, config.clone(), 15); let state = abci_app.platform.state.load(); @@ -1395,13 +1438,14 @@ mod tests { core_height_start: 1, block_count: 1100, proposers, - quorums, - current_quorum_hash, + validator_quorums: quorums, + current_validator_quorum_hash: current_quorum_hash, current_proposer_versions: None, current_identity_nonce_counter: identity_nonce_counter, current_identity_contract_nonce_counter: identity_contract_nonce_counter, start_time_ms: 1681094380000, current_time_ms: end_time_ms, + instant_lock_quorums, }, strategy, config, diff --git a/packages/rs-platform-version/src/version/drive_abci_versions.rs b/packages/rs-platform-version/src/version/drive_abci_versions.rs index 2439f050b17..5953f56e91c 100644 --- a/packages/rs-platform-version/src/version/drive_abci_versions.rs +++ b/packages/rs-platform-version/src/version/drive_abci_versions.rs @@ -53,6 +53,7 @@ pub struct DriveAbciStructureVersions { pub state_transition_execution_context: FeatureVersion, pub commit: FeatureVersion, pub masternode: FeatureVersion, + pub signature_verification_quorum_set: FeatureVersion, } #[derive(Clone, Debug, Default)] @@ -64,6 +65,7 @@ pub struct DriveAbciMethodVersions { pub block_fee_processing: DriveAbciBlockFeeProcessingMethodVersions, pub core_subsidy: DriveAbciCoreSubsidyMethodVersions, pub core_chain_lock: DriveAbciCoreChainLockMethodVersionsAndConstants, + pub core_instant_send_lock: DriveAbciCoreInstantSendLockMethodVersions, pub fee_pool_inwards_distribution: DriveAbciFeePoolInwardsDistributionMethodVersions, pub fee_pool_outwards_distribution: DriveAbciFeePoolOutwardsDistributionMethodVersions, pub withdrawals: DriveAbciIdentityCreditWithdrawalMethodVersions, @@ -231,6 +233,11 @@ pub struct DriveAbciCoreSubsidyMethodVersions { pub epoch_core_reward_credits_for_distribution: FeatureVersion, } +#[derive(Clone, Debug, Default)] +pub struct DriveAbciCoreInstantSendLockMethodVersions { + pub verify_recent_signature_locally: FeatureVersion, +} + #[derive(Clone, Debug, Default)] pub struct DriveAbciCoreChainLockMethodVersionsAndConstants { pub choose_quorum: FeatureVersion, diff --git a/packages/rs-platform-version/src/version/mocks/v2_test.rs b/packages/rs-platform-version/src/version/mocks/v2_test.rs index d47370d65b7..41e1a4f381b 100644 --- a/packages/rs-platform-version/src/version/mocks/v2_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v2_test.rs @@ -15,9 +15,9 @@ use crate::version::drive_abci_versions::{ DriveAbciAssetLockValidationVersions, DriveAbciBlockEndMethodVersions, DriveAbciBlockFeeProcessingMethodVersions, DriveAbciBlockStartMethodVersions, DriveAbciCoreBasedUpdatesMethodVersions, DriveAbciCoreChainLockMethodVersionsAndConstants, - DriveAbciCoreSubsidyMethodVersions, DriveAbciDocumentsStateTransitionValidationVersions, - DriveAbciEngineMethodVersions, DriveAbciEpochMethodVersions, - DriveAbciFeePoolInwardsDistributionMethodVersions, + DriveAbciCoreInstantSendLockMethodVersions, DriveAbciCoreSubsidyMethodVersions, + DriveAbciDocumentsStateTransitionValidationVersions, DriveAbciEngineMethodVersions, + DriveAbciEpochMethodVersions, DriveAbciFeePoolInwardsDistributionMethodVersions, DriveAbciFeePoolOutwardsDistributionMethodVersions, DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, @@ -502,6 +502,7 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { state_transition_execution_context: 0, commit: 0, masternode: 0, + signature_verification_quorum_set: 0, }, methods: DriveAbciMethodVersions { engine: DriveAbciEngineMethodVersions { @@ -555,6 +556,9 @@ pub const TEST_PLATFORM_V2: PlatformVersion = PlatformVersion { make_sure_core_is_synced_to_chain_lock: 0, recent_block_count_amount: 2, }, + core_instant_send_lock: DriveAbciCoreInstantSendLockMethodVersions { + verify_recent_signature_locally: 0, + }, fee_pool_inwards_distribution: DriveAbciFeePoolInwardsDistributionMethodVersions { add_distribute_block_fees_into_pools_operations: 0, add_distribute_storage_fee_to_epochs_operations: 0, diff --git a/packages/rs-platform-version/src/version/mocks/v3_test.rs b/packages/rs-platform-version/src/version/mocks/v3_test.rs index d603bf780e8..c027f7886fc 100644 --- a/packages/rs-platform-version/src/version/mocks/v3_test.rs +++ b/packages/rs-platform-version/src/version/mocks/v3_test.rs @@ -15,9 +15,9 @@ use crate::version::drive_abci_versions::{ DriveAbciAssetLockValidationVersions, DriveAbciBlockEndMethodVersions, DriveAbciBlockFeeProcessingMethodVersions, DriveAbciBlockStartMethodVersions, DriveAbciCoreBasedUpdatesMethodVersions, DriveAbciCoreChainLockMethodVersionsAndConstants, - DriveAbciCoreSubsidyMethodVersions, DriveAbciDocumentsStateTransitionValidationVersions, - DriveAbciEngineMethodVersions, DriveAbciEpochMethodVersions, - DriveAbciFeePoolInwardsDistributionMethodVersions, + DriveAbciCoreInstantSendLockMethodVersions, DriveAbciCoreSubsidyMethodVersions, + DriveAbciDocumentsStateTransitionValidationVersions, DriveAbciEngineMethodVersions, + DriveAbciEpochMethodVersions, DriveAbciFeePoolInwardsDistributionMethodVersions, DriveAbciFeePoolOutwardsDistributionMethodVersions, DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, @@ -502,6 +502,7 @@ pub const TEST_PLATFORM_V3: PlatformVersion = PlatformVersion { state_transition_execution_context: 0, commit: 0, masternode: 0, + signature_verification_quorum_set: 0, }, methods: DriveAbciMethodVersions { engine: DriveAbciEngineMethodVersions { @@ -555,6 +556,9 @@ pub const TEST_PLATFORM_V3: PlatformVersion = PlatformVersion { make_sure_core_is_synced_to_chain_lock: 0, recent_block_count_amount: 2, }, + core_instant_send_lock: DriveAbciCoreInstantSendLockMethodVersions { + verify_recent_signature_locally: 0, + }, fee_pool_inwards_distribution: DriveAbciFeePoolInwardsDistributionMethodVersions { add_distribute_block_fees_into_pools_operations: 0, add_distribute_storage_fee_to_epochs_operations: 0, diff --git a/packages/rs-platform-version/src/version/v1.rs b/packages/rs-platform-version/src/version/v1.rs index 268ae2a7c57..a539e8bc29e 100644 --- a/packages/rs-platform-version/src/version/v1.rs +++ b/packages/rs-platform-version/src/version/v1.rs @@ -15,9 +15,9 @@ use crate::version::drive_abci_versions::{ DriveAbciAssetLockValidationVersions, DriveAbciBlockEndMethodVersions, DriveAbciBlockFeeProcessingMethodVersions, DriveAbciBlockStartMethodVersions, DriveAbciCoreBasedUpdatesMethodVersions, DriveAbciCoreChainLockMethodVersionsAndConstants, - DriveAbciCoreSubsidyMethodVersions, DriveAbciDocumentsStateTransitionValidationVersions, - DriveAbciEngineMethodVersions, DriveAbciEpochMethodVersions, - DriveAbciFeePoolInwardsDistributionMethodVersions, + DriveAbciCoreInstantSendLockMethodVersions, DriveAbciCoreSubsidyMethodVersions, + DriveAbciDocumentsStateTransitionValidationVersions, DriveAbciEngineMethodVersions, + DriveAbciEpochMethodVersions, DriveAbciFeePoolInwardsDistributionMethodVersions, DriveAbciFeePoolOutwardsDistributionMethodVersions, DriveAbciIdentityCreditWithdrawalMethodVersions, DriveAbciInitializationMethodVersions, DriveAbciMasternodeIdentitiesUpdatesMethodVersions, DriveAbciMethodVersions, @@ -501,6 +501,7 @@ pub const PLATFORM_V1: PlatformVersion = PlatformVersion { state_transition_execution_context: 0, commit: 0, masternode: 0, + signature_verification_quorum_set: 0, }, methods: DriveAbciMethodVersions { engine: DriveAbciEngineMethodVersions { @@ -554,6 +555,9 @@ pub const PLATFORM_V1: PlatformVersion = PlatformVersion { make_sure_core_is_synced_to_chain_lock: 0, recent_block_count_amount: 2, }, + core_instant_send_lock: DriveAbciCoreInstantSendLockMethodVersions { + verify_recent_signature_locally: 0, + }, fee_pool_inwards_distribution: DriveAbciFeePoolInwardsDistributionMethodVersions { add_distribute_block_fees_into_pools_operations: 0, add_distribute_storage_fee_to_epochs_operations: 0, diff --git a/packages/strategy-tests/src/transitions.rs b/packages/strategy-tests/src/transitions.rs index 0ef26db956b..0a9ef44be30 100644 --- a/packages/strategy-tests/src/transitions.rs +++ b/packages/strategy-tests/src/transitions.rs @@ -779,7 +779,7 @@ pub fn create_state_transitions_for_identities( let (_, pk) = ECDSA_SECP256K1 .random_public_and_private_key_data(rng, platform_version) .unwrap(); - let sk: [u8; 32] = pk.clone().try_into().unwrap(); + let sk: [u8; 32] = pk.try_into().unwrap(); let secret_key = SecretKey::from_str(hex::encode(sk).as_str()).unwrap(); let asset_lock_proof = instant_asset_lock_proof_fixture(PrivateKey::new(secret_key, Network::Dash)); @@ -787,7 +787,33 @@ pub fn create_state_transitions_for_identities( IdentityCreateTransition::try_from_identity_with_signer( &identity.clone(), asset_lock_proof, - pk.as_slice(), + &sk, + signer, + &NativeBlsModule, + 0, + platform_version, + ) + .expect("expected to transform identity into identity create transition"); + identity.set_id(identity_create_transition.owner_id()); + + (identity, identity_create_transition) + }) + .collect() +} + +pub fn create_state_transitions_for_identities_and_proofs( + identities_with_proofs: Vec<(Identity, [u8; 32], AssetLockProof)>, + signer: &mut SimpleSigner, + platform_version: &PlatformVersion, +) -> Vec<(Identity, StateTransition)> { + identities_with_proofs + .into_iter() + .map(|(mut identity, private_key, asset_lock_proof)| { + let identity_create_transition = + IdentityCreateTransition::try_from_identity_with_signer( + &identity.clone(), + asset_lock_proof, + &private_key, signer, &NativeBlsModule, 0,