diff --git a/operator/Cargo.lock b/operator/Cargo.lock
index e0ed14dd..91e02930 100644
--- a/operator/Cargo.lock
+++ b/operator/Cargo.lock
@@ -2345,6 +2345,7 @@ dependencies = [
"pallet-ethereum",
"pallet-evm",
"pallet-evm-chain-id",
+ "pallet-external-validators",
"pallet-grandpa",
"pallet-identity",
"pallet-im-online",
@@ -2362,7 +2363,6 @@ dependencies = [
"pallet-transaction-payment",
"pallet-transaction-payment-rpc-runtime-api",
"pallet-utility",
- "pallet-validator-set",
"parity-scale-codec",
"polkadot-primitives",
"polkadot-runtime-common",
@@ -2524,6 +2524,7 @@ dependencies = [
"pallet-ethereum",
"pallet-evm",
"pallet-evm-chain-id",
+ "pallet-external-validators",
"pallet-grandpa",
"pallet-identity",
"pallet-im-online",
@@ -2541,7 +2542,6 @@ dependencies = [
"pallet-transaction-payment",
"pallet-transaction-payment-rpc-runtime-api",
"pallet-utility",
- "pallet-validator-set",
"parity-scale-codec",
"polkadot-primitives",
"polkadot-runtime-common",
@@ -2612,6 +2612,7 @@ dependencies = [
"pallet-ethereum",
"pallet-evm",
"pallet-evm-chain-id",
+ "pallet-external-validators",
"pallet-grandpa",
"pallet-identity",
"pallet-im-online",
@@ -2629,7 +2630,6 @@ dependencies = [
"pallet-transaction-payment",
"pallet-transaction-payment-rpc-runtime-api",
"pallet-utility",
- "pallet-validator-set",
"parity-scale-codec",
"polkadot-primitives",
"polkadot-runtime-common",
@@ -2811,7 +2811,7 @@ version = "0.1.0"
dependencies = [
"frame-support",
"frame-system",
- "pallet-validator-set",
+ "pallet-external-validators",
"parity-scale-codec",
"snowbridge-core 0.2.0",
"snowbridge-inbound-queue-primitives",
@@ -7614,6 +7614,28 @@ dependencies = [
"scale-info",
]
+[[package]]
+name = "pallet-external-validators"
+version = "0.1.0"
+dependencies = [
+ "frame-benchmarking",
+ "frame-support",
+ "frame-system",
+ "impl-trait-for-tuples",
+ "log",
+ "pallet-balances",
+ "pallet-session",
+ "pallet-timestamp",
+ "parity-scale-codec",
+ "rand 0.8.5",
+ "scale-info",
+ "sp-core",
+ "sp-io",
+ "sp-runtime",
+ "sp-staking",
+ "sp-std",
+]
+
[[package]]
name = "pallet-fast-unstake"
version = "38.1.0"
@@ -7977,23 +7999,6 @@ dependencies = [
"sp-runtime",
]
-[[package]]
-name = "pallet-validator-set"
-version = "1.0.0"
-dependencies = [
- "frame-benchmarking",
- "frame-support",
- "frame-system",
- "log",
- "pallet-session",
- "parity-scale-codec",
- "scale-info",
- "sp-core",
- "sp-io",
- "sp-runtime",
- "sp-staking",
-]
-
[[package]]
name = "pallet-vesting"
version = "39.1.0"
diff --git a/operator/Cargo.toml b/operator/Cargo.toml
index ff10a2f7..64e817ff 100644
--- a/operator/Cargo.toml
+++ b/operator/Cargo.toml
@@ -24,8 +24,8 @@ datahaven-runtime-common = { path = "./runtime/common", default-features = false
datahaven-stagenet-runtime = { path = "./runtime/stagenet", default-features = false }
datahaven-testnet-runtime = { path = "./runtime/testnet", default-features = false }
dhp-bridge = { path = "./primitives/bridge", default-features = false }
+pallet-external-validators = { path = "./pallets/external-validators", default-features = false }
pallet-outbound-commitment-store = { path = "./pallets/outbound-commitment-store", default-features = false }
-pallet-validator-set = { path = "./pallets/validator-set", default-features = false }
# Crates.io (wasm)
alloy-core = { version = "0.8.15", default-features = false }
diff --git a/operator/pallets/external-validators/Cargo.toml b/operator/pallets/external-validators/Cargo.toml
new file mode 100644
index 00000000..34de46ea
--- /dev/null
+++ b/operator/pallets/external-validators/Cargo.toml
@@ -0,0 +1,75 @@
+[package]
+name = "pallet-external-validators"
+authors = { workspace = true }
+description = "Simple pallet to store external validators."
+edition = "2021"
+license = "GPL-3.0-only"
+version = "0.1.0"
+
+[package.metadata.docs.rs]
+targets = [ "x86_64-unknown-linux-gnu" ]
+
+[lints]
+workspace = true
+
+[dependencies]
+log = { workspace = true }
+parity-scale-codec = { workspace = true }
+rand = { workspace = true, optional = true }
+scale-info = { workspace = true, features = [ "derive" ] }
+
+frame-support = { workspace = true }
+frame-system = { workspace = true }
+impl-trait-for-tuples = { workspace = true }
+sp-runtime = { workspace = true }
+sp-staking = { workspace = true }
+sp-std = { workspace = true }
+
+frame-benchmarking = { workspace = true }
+
+pallet-balances = { workspace = true, optional = true }
+pallet-session = { workspace = true, features = [ "historical" ] }
+
+[dev-dependencies]
+pallet-timestamp = { workspace = true }
+sp-core = { workspace = true }
+sp-io = { workspace = true }
+
+[features]
+default = [ "std" ]
+std = [
+ "frame-benchmarking/std",
+ "frame-support/std",
+ "frame-system/std",
+ "log/std",
+ "pallet-balances/std",
+ "pallet-session/std",
+ "pallet-timestamp/std",
+ "parity-scale-codec/std",
+ "rand?/std",
+ "scale-info/std",
+ "sp-core/std",
+ "sp-io/std",
+ "sp-runtime/std",
+ "sp-staking/std",
+ "sp-std/std",
+]
+runtime-benchmarks = [
+ "frame-benchmarking/runtime-benchmarks",
+ "frame-support/runtime-benchmarks",
+ "frame-system/runtime-benchmarks",
+ "pallet-balances/runtime-benchmarks",
+ "pallet-timestamp/runtime-benchmarks",
+ "rand",
+ "sp-runtime/runtime-benchmarks",
+ "sp-staking/runtime-benchmarks",
+]
+
+try-runtime = [
+ "frame-support/try-runtime",
+ "frame-system/try-runtime",
+ "pallet-balances?/try-runtime",
+ "pallet-session/try-runtime",
+ "pallet-timestamp/try-runtime",
+ "sp-runtime/try-runtime",
+]
diff --git a/operator/pallets/external-validators/src/benchmarking.rs b/operator/pallets/external-validators/src/benchmarking.rs
new file mode 100644
index 00000000..14c4df6b
--- /dev/null
+++ b/operator/pallets/external-validators/src/benchmarking.rs
@@ -0,0 +1,252 @@
+// Copyright (C) Moondance Labs Ltd.
+// This file is part of Tanssi.
+
+// Tanssi is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Tanssi is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Tanssi. If not, see
+
+//! Benchmarking setup for pallet_external_validators
+
+use super::*;
+
+#[allow(unused)]
+use crate::Pallet as ExternalValidators;
+use {
+ frame_benchmarking::{account, v2::*, BenchmarkError},
+ frame_support::traits::{Currency, EnsureOrigin, Get},
+ frame_system::{EventRecord, RawOrigin},
+ pallet_session::{self as session, SessionManager},
+ rand::{RngCore, SeedableRng},
+ sp_runtime::{codec, traits::Convert},
+ sp_std::prelude::*,
+};
+const SEED: u32 = 0;
+
+fn assert_last_event(generic_event: ::RuntimeEvent) {
+ let events = frame_system::Pallet::::events();
+ let system_event: ::RuntimeEvent = generic_event.into();
+ // compare to the last event record
+ let EventRecord { event, .. } = &events[events.len() - 1];
+ assert_eq!(event, &system_event);
+}
+
+fn create_funded_user(
+ string: &'static str,
+ n: u32,
+ balance_factor: u32,
+) -> T::AccountId {
+ let user = account(string, n, SEED);
+ let balance = as Currency>::minimum_balance()
+ * balance_factor.into();
+ let _ = as Currency>::make_free_balance_be(
+ &user, balance,
+ );
+ user
+}
+
+struct InputFromRng<'a, T>(&'a mut T);
+impl<'a, T: RngCore> codec::Input for InputFromRng<'a, T> {
+ fn remaining_len(&mut self) -> Result