From 7c52863d7dca1dc4cee3ef17847a6267828af03a Mon Sep 17 00:00:00 2001 From: DxFFFFFF Date: Thu, 18 Jan 2024 17:50:22 +0100 Subject: [PATCH] Validator Controller solidity interface for checking when validator is missing blocks (#163) --- docker/README.md | 1 + docs/GETTING-STARTED.md | 1 + docs/README.md | 2 +- .../ValidatorController.sol | 4 ++ precompiles/validator-controller/src/lib.rs | 28 +++++++--- precompiles/validator-controller/src/tests.rs | 53 +++++++++++++++++-- 6 files changed, 78 insertions(+), 11 deletions(-) diff --git a/docker/README.md b/docker/README.md index 24163673..66fe9b8a 100644 --- a/docker/README.md +++ b/docker/README.md @@ -36,6 +36,7 @@ Optional environment variables: - NODE_KEY: This environment variable allows specifying the node key to use. If not specified, the node will generate a random node key. This applies to the P2P key, not the account key. - BOOTNODES: This environment variable allows specifying the bootnodes to use, separated by commas. If not specified, the node will use the default bootnodes for the chain spec. - MODE: This environment variable allows the node to run in different pruning modes. Possible values are "full_node" or "archive". The default value is "full_node". +- BACKEND_TYPE: The only available option is `sql` for now. This option allows the node to use a SQL backend instead of the default `key-value` backend for faster Ethereum log queries. - ZERO_GAS_TX_POOL: This environment variable allows the node to run with a zero gas price transaction pool. By default the feature is disabled. The expected value is a string containing an URL. Check the [Zero Gas Transaction Pool](../docs/ZERO-GAS-TRANSACTIONS.md) document for more information. - ZERO_GAS_TX_POOL_TIMEOUT: This environment variable allows specifying the timeout for the zero gas transaction in millisecond. If not specified, the node will use the default timeout (1000ms). diff --git a/docs/GETTING-STARTED.md b/docs/GETTING-STARTED.md index c8c82fa3..b91a84c0 100644 --- a/docs/GETTING-STARTED.md +++ b/docs/GETTING-STARTED.md @@ -71,6 +71,7 @@ Additionally, you can configure the following flags: - `--unsafe-rpc-external --rpc-cors all`: Use if your node will be accessed from a system external to your localhost. - `--bootnodes`: A list of p2p nodes for Stability to join the network. What is known as bootnodes - `--base-path`: Specifies a custom base path for the data folder +- `--frontier-backend-type`: The standard database with the system can be modified to use an SQL backend. Since getting Ethereum logs is an everyday use case with a high CPU usage, SQL backend mode is optimized for this. Available options are `sql` or `key-value` (default). ## Generating the a build spec file or Genesis file diff --git a/docs/README.md b/docs/README.md index 4a4e343a..f3bfd104 100644 --- a/docs/README.md +++ b/docs/README.md @@ -13,4 +13,4 @@ - [Zero Gas Transactions](ZERO-GAS-TRANSACTIONS.md) - [Custom RPCs](RPC.md) - [Validator connection handling](VALIDATOR-CONNECTION-HANDLING.md) -- [Audits][AUDITS.md] +- [Audits](AUDITS.md) diff --git a/precompiles/validator-controller/ValidatorController.sol b/precompiles/validator-controller/ValidatorController.sol index e2f8fd36..3eb366b0 100644 --- a/precompiles/validator-controller/ValidatorController.sol +++ b/precompiles/validator-controller/ValidatorController.sol @@ -9,4 +9,8 @@ interface ValidatorController { function getValidatorList() external view returns (address[] memory); function getActiveValidatorList() external view returns (address[] memory); + + function getValidatorMissingBlocks( + address validator + ) external view returns (uint256); } diff --git a/precompiles/validator-controller/src/lib.rs b/precompiles/validator-controller/src/lib.rs index 2fd80922..f40c125a 100644 --- a/precompiles/validator-controller/src/lib.rs +++ b/precompiles/validator-controller/src/lib.rs @@ -32,6 +32,7 @@ use frame_support::storage::types::{StorageValue, ValueQuery}; use frame_support::traits::StorageInstance; use pallet_custom_balances::AccountIdMapping; +use pallet_evm::AddressMapping; use precompile_utils::prelude::*; use sp_core::Get; @@ -87,7 +88,8 @@ where Runtime: pallet_validator_set::Config + pallet_timestamp::Config + pallet_evm::Config - + pallet_custom_balances::Config, + + pallet_custom_balances::Config + + pallet_evm::Config, Runtime::RuntimeCall: From>, ::RuntimeOrigin: From>, Runtime::RuntimeCall: Dispatchable + GetDispatchInfo, @@ -133,7 +135,7 @@ where handle.context().address, SELECTOR_LOG_TRANSFER_OWNER, Into::::into(owner), - solidity::encode_event_data(Into::::into(target_new_owner)) + solidity::encode_event_data(Into::::into(target_new_owner)), ) .record(handle)?; @@ -163,8 +165,9 @@ where log1( handle.context().address, SELECTOR_LOG_NEW_OWNER, - solidity::encode_event_data(Into::::into(target_new_owner)) - ).record(handle)?; + solidity::encode_event_data(Into::::into(target_new_owner)), + ) + .record(handle)?; Ok(()) } @@ -203,6 +206,19 @@ where .collect()) } + #[precompile::public("getValidatorMissingBlocks(address)")] + #[precompile::view] + fn get_validator_missing_blocks( + handle: &mut impl PrecompileHandle, + validator: Address, + ) -> EvmResult { + handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; + let account_id = + ::AddressMapping::into_account_id(validator.into()); + let epochs_missed = pallet_validator_set::EpochsMissed::::get(account_id); + Ok(epochs_missed) + } + #[precompile::public("addValidator(address)")] fn add_validator(handle: &mut impl PrecompileHandle, new_validator: Address) -> EvmResult { handle.record_cost(RuntimeHelper::::db_read_gas_cost())?; @@ -229,7 +245,7 @@ where log1( handle.context().address, SELECTOR_VALIDATOR_ADDED, - solidity::encode_event_data(Into::::into(origin_id)) + solidity::encode_event_data(Into::::into(origin_id)), ) .record(handle)?; @@ -265,7 +281,7 @@ where log1( handle.context().address, SELECTOR_VALIDATOR_REMOVED, - solidity::encode_event_data(Into::::into(origin_id)) + solidity::encode_event_data(Into::::into(origin_id)), ) .record(handle)?; diff --git a/precompiles/validator-controller/src/tests.rs b/precompiles/validator-controller/src/tests.rs index e3efa80c..cde3c68d 100644 --- a/precompiles/validator-controller/src/tests.rs +++ b/precompiles/validator-controller/src/tests.rs @@ -20,6 +20,7 @@ fn selectors() { assert!(PCall::add_validator_selectors().contains(&0x4d238c8e)); assert!(PCall::remove_validator_selectors().contains(&0x40a141ff)); assert!(PCall::get_validator_list_selectors().contains(&0xe35c0f7d)); + assert!(PCall::get_validator_missing_blocks_selectors().contains(&0x41ee9a53)); assert_eq!( crate::SELECTOR_LOG_NEW_OWNER, &Keccak256::digest(b"NewOwner(address)")[..] @@ -33,6 +34,7 @@ fn modifiers() { tester.test_view_modifier(PCall::owner_selectors()); tester.test_view_modifier(PCall::pending_owner_selectors()); + tester.test_view_modifier(PCall::get_validator_missing_blocks_selectors()); tester.test_default_modifier(PCall::transfer_ownership_selectors()); tester.test_default_modifier(PCall::claim_ownership_selectors()); tester.test_default_modifier(PCall::add_validator_selectors()); @@ -138,7 +140,7 @@ fn claim_ownership_if_claimable() { .expect_log(log1( Precompile1, SELECTOR_LOG_NEW_OWNER, - solidity::encode_event_data(Into::::into(new_owner)) + solidity::encode_event_data(Into::::into(new_owner)), )) .execute_some(); @@ -164,7 +166,7 @@ fn add_validator() { .expect_log(log1( Precompile1, SELECTOR_VALIDATOR_ADDED, - solidity::encode_event_data(account_id_to_evm_address(validator.clone())) + solidity::encode_event_data(account_id_to_evm_address(validator.clone())), )) .execute_some(); @@ -217,7 +219,7 @@ fn add_validator_if_already_init() { .expect_log(log1( Precompile1, SELECTOR_VALIDATOR_ADDED, - solidity::encode_event_data(account_id_to_evm_address(validator.clone())) + solidity::encode_event_data(account_id_to_evm_address(validator.clone())), )) .execute_some(); @@ -302,7 +304,7 @@ fn remove_validator() { .expect_log(log1( Precompile1, SELECTOR_VALIDATOR_REMOVED, - solidity::encode_event_data(account_id_to_evm_address(validator.clone())) + solidity::encode_event_data(account_id_to_evm_address(validator.clone())), )) .execute_some(); @@ -369,3 +371,46 @@ fn get_default_active_validator_list() { ); }); } + +#[test] +fn checks_if_validator_is_missing_blocks() { + let sender = UnpermissionedAccount::get(); + let validator = ValidatorInitial::get(); + let validators = vec![validator.clone()]; + ExtBuilder::default() + .with_validators(validators.clone()) + .build() + .execute_with(|| { + precompiles() + .prepare_test( + sender, + Precompile1, + PCall::get_validator_missing_blocks { + validator: account_id_to_evm_address(validator.clone()), + }, + ) + .execute_returns(U256::zero()); + }); +} + +#[test] +fn checks_a_validator_missing_blocks() { + let sender = UnpermissionedAccount::get(); + let validator = ValidatorInitial::get(); + let validators = vec![validator.clone()]; + ExtBuilder::default() + .with_validators(validators.clone()) + .build() + .execute_with(|| { + pallet_validator_set::EpochsMissed::::set(validator.clone(), U256::from(2)); + precompiles() + .prepare_test( + sender, + Precompile1, + PCall::get_validator_missing_blocks { + validator: account_id_to_evm_address(validator.clone()), + }, + ) + .execute_returns(U256::from(2)); + }); +}