diff --git a/Cargo.lock b/Cargo.lock
index fc9820446..2a9e669c4 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3405,6 +3405,7 @@ dependencies = [
"pallet-external-validator-slashes",
"pallet-external-validators",
"pallet-external-validators-rewards",
+ "pallet-external-validators-rewards-runtime-api",
"pallet-grandpa",
"pallet-identity",
"pallet-inflation-rewards",
@@ -9605,6 +9606,7 @@ dependencies = [
"frame-benchmarking",
"frame-support",
"frame-system",
+ "log",
"pallet-balances",
"pallet-session",
"pallet-timestamp",
@@ -9612,14 +9614,27 @@ dependencies = [
"polkadot-primitives",
"polkadot-runtime-parachains",
"scale-info",
+ "snowbridge-core",
+ "snowbridge-outbound-queue-merkle-tree",
"sp-core",
"sp-io",
"sp-runtime",
"sp-staking",
"sp-std",
+ "tp-bridge",
"tp-traits",
]
+[[package]]
+name = "pallet-external-validators-rewards-runtime-api"
+version = "0.1.0"
+dependencies = [
+ "parity-scale-codec",
+ "snowbridge-outbound-queue-merkle-tree",
+ "sp-api",
+ "sp-core",
+]
+
[[package]]
name = "pallet-fast-unstake"
version = "37.0.0"
diff --git a/Cargo.toml b/Cargo.toml
index b36c2ea95..c62dc5ee4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -63,6 +63,7 @@ pallet-data-preservers-runtime-api = { path = "pallets/data-preservers/runtime-a
pallet-external-validator-slashes = { path = "pallets/external-validator-slashes", default-features = false }
pallet-external-validators = { path = "pallets/external-validators", default-features = false }
pallet-external-validators-rewards = { path = "pallets/external-validators-rewards", default-features = false }
+pallet-external-validators-rewards-runtime-api = { path = "pallets/external-validators-rewards/runtime-api", default-features = false }
pallet-inflation-rewards = { path = "pallets/inflation-rewards", default-features = false }
pallet-initializer = { path = "pallets/initializer", default-features = false }
pallet-invulnerables = { path = "pallets/invulnerables", default-features = false }
@@ -260,9 +261,11 @@ xcm-runtime-apis = { git = "https://github.com/moondance-labs/polkadot-sdk", bra
# Bridges (wasm)
alloy-sol-types = { version = "0.4.2", default-features = false }
+bridge-hub-common = { git = "https://github.com/moondance-labs/polkadot-sdk", branch = "tanssi-polkadot-stable2407", default-features = false }
milagro-bls = { package = "snowbridge-milagro-bls", version = "1.5.4", default-features = false }
snowbridge-beacon-primitives = { git = "https://github.com/moondance-labs/polkadot-sdk", branch = "tanssi-polkadot-stable2409", default-features = false }
snowbridge-core = { git = "https://github.com/moondance-labs/polkadot-sdk", branch = "tanssi-polkadot-stable2409", default-features = false }
+snowbridge-outbound-queue-merkle-tree = { git = "https://github.com/moondance-labs/polkadot-sdk", branch = "tanssi-polkadot-stable2409", default-features = false }
snowbridge-pallet-ethereum-client = { git = "https://github.com/moondance-labs/polkadot-sdk", branch = "tanssi-polkadot-stable2409", default-features = false }
snowbridge-pallet-inbound-queue = { git = "https://github.com/moondance-labs/polkadot-sdk", branch = "tanssi-polkadot-stable2409", default-features = false }
snowbridge-pallet-inbound-queue-fixtures = { git = "https://github.com/moondance-labs/polkadot-sdk", branch = "tanssi-polkadot-stable2409", default-features = false }
diff --git a/pallets/external-validators-rewards/Cargo.toml b/pallets/external-validators-rewards/Cargo.toml
index 579f871b0..43f6da0ce 100644
--- a/pallets/external-validators-rewards/Cargo.toml
+++ b/pallets/external-validators-rewards/Cargo.toml
@@ -13,14 +13,17 @@ targets = [ "x86_64-unknown-linux-gnu" ]
workspace = true
[dependencies]
+log = { workspace = true }
parity-scale-codec = { workspace = true }
scale-info = { workspace = true, features = [ "derive" ] }
frame-support = { workspace = true }
frame-system = { workspace = true }
+sp-core = { workspace = true }
sp-runtime = { workspace = true }
sp-staking = { workspace = true }
sp-std = { workspace = true }
+tp-bridge = { workspace = true }
tp-traits = { workspace = true }
frame-benchmarking = { workspace = true }
@@ -29,11 +32,13 @@ pallet-balances = { workspace = true, optional = true }
pallet-session = { workspace = true, features = [ "historical" ] }
runtime-parachains = { workspace = true }
+snowbridge-core = { workspace = true }
+snowbridge-outbound-queue-merkle-tree = { workspace = true }
+
polkadot-primitives = { workspace = true }
[dev-dependencies]
pallet-timestamp = { workspace = true }
-sp-core = { workspace = true }
sp-io = { workspace = true }
[features]
@@ -42,6 +47,7 @@ std = [
"frame-benchmarking/std",
"frame-support/std",
"frame-system/std",
+ "log/std",
"pallet-balances/std",
"pallet-session/std",
"pallet-timestamp/std",
@@ -49,11 +55,14 @@ std = [
"polkadot-primitives/std",
"runtime-parachains/std",
"scale-info/std",
+ "snowbridge-core/std",
+ "snowbridge-outbound-queue-merkle-tree/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
"sp-staking/std",
"sp-std/std",
+ "tp-bridge/std",
"tp-traits/std",
]
runtime-benchmarks = [
@@ -64,8 +73,10 @@ runtime-benchmarks = [
"pallet-timestamp/runtime-benchmarks",
"polkadot-primitives/runtime-benchmarks",
"runtime-parachains/runtime-benchmarks",
+ "snowbridge-core/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"sp-staking/runtime-benchmarks",
+ "tp-bridge/runtime-benchmarks",
"tp-traits/runtime-benchmarks",
]
diff --git a/pallets/external-validators-rewards/runtime-api/Cargo.toml b/pallets/external-validators-rewards/runtime-api/Cargo.toml
new file mode 100644
index 000000000..4fe0c85a8
--- /dev/null
+++ b/pallets/external-validators-rewards/runtime-api/Cargo.toml
@@ -0,0 +1,28 @@
+[package]
+name = "pallet-external-validators-rewards-runtime-api"
+authors = { workspace = true }
+description = "Runtime API definition of pallet-external-validators-rewards"
+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]
+parity-scale-codec = { workspace = true }
+snowbridge-outbound-queue-merkle-tree = { workspace = true }
+sp-api = { workspace = true }
+sp-core = { workspace = true }
+
+[features]
+default = [ "std" ]
+std = [
+ "parity-scale-codec/std",
+ "snowbridge-outbound-queue-merkle-tree/std",
+ "sp-api/std",
+ "sp-core/std",
+]
diff --git a/pallets/external-validators-rewards/runtime-api/src/lib.rs b/pallets/external-validators-rewards/runtime-api/src/lib.rs
new file mode 100644
index 000000000..3d8c6e1b6
--- /dev/null
+++ b/pallets/external-validators-rewards/runtime-api/src/lib.rs
@@ -0,0 +1,32 @@
+// 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
+
+//! Runtime API for External Validators Rewards pallet
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+use snowbridge_outbound_queue_merkle_tree::MerkleProof;
+
+sp_api::decl_runtime_apis! {
+ pub trait ExternalValidatorsRewardsApi
+ where
+ AccountId: parity_scale_codec::Codec,
+ EraIndex: parity_scale_codec::Codec,
+ {
+ fn generate_rewards_merkle_proof(account_id: AccountId, era_index: EraIndex) -> Option;
+ fn verify_rewards_merkle_proof(merkle_proof: MerkleProof) -> bool;
+ }
+}
diff --git a/pallets/external-validators-rewards/src/benchmarking.rs b/pallets/external-validators-rewards/src/benchmarking.rs
new file mode 100644
index 000000000..4c068b026
--- /dev/null
+++ b/pallets/external-validators-rewards/src/benchmarking.rs
@@ -0,0 +1,81 @@
+// 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_rewards
+
+use super::*;
+
+#[allow(unused)]
+use crate::Pallet as ExternalValidatorsRewards;
+use {
+ frame_benchmarking::{account, v2::*, BenchmarkError},
+ frame_support::traits::{Currency, Get},
+ sp_std::prelude::*,
+ tp_traits::OnEraEnd,
+};
+
+const SEED: u32 = 0;
+
+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
+}
+
+#[allow(clippy::multiple_bound_locations)]
+#[benchmarks(where T: pallet_balances::Config)]
+mod benchmarks {
+ use super::*;
+
+ // worst case for the end of an era.
+ #[benchmark]
+ fn on_era_end() -> Result<(), BenchmarkError> {
+ frame_system::Pallet::::set_block_number(0u32.into());
+
+ let mut era_reward_points = EraRewardPoints::default();
+ era_reward_points.total = T::BackingPoints::get() * 1000;
+
+ for i in 0..1000 {
+ let account_id = create_funded_user::("candidate", i, 100);
+ era_reward_points
+ .individual
+ .insert(account_id, T::BackingPoints::get());
+ }
+
+ >::insert(1u32, era_reward_points);
+
+ #[block]
+ {
+ as OnEraEnd>::on_era_end(1u32);
+ }
+
+ Ok(())
+ }
+
+ impl_benchmark_test_suite!(
+ ExternalValidatorsRewards,
+ crate::mock::new_test_ext(),
+ crate::mock::Test,
+ );
+}
diff --git a/pallets/external-validators-rewards/src/lib.rs b/pallets/external-validators-rewards/src/lib.rs
index 4888c206a..7f2162eff 100644
--- a/pallets/external-validators-rewards/src/lib.rs
+++ b/pallets/external-validators-rewards/src/lib.rs
@@ -25,20 +25,43 @@ mod mock;
#[cfg(test)]
mod tests;
+#[cfg(feature = "runtime-benchmarks")]
+mod benchmarking;
+
+pub mod weights;
+
pub use pallet::*;
use {
frame_support::traits::{Defensive, Get, ValidatorSet},
+ parity_scale_codec::Encode,
polkadot_primitives::ValidatorIndex,
runtime_parachains::session_info,
+ snowbridge_core::ChannelId,
+ snowbridge_outbound_queue_merkle_tree::{merkle_proof, merkle_root, verify_proof, MerkleProof},
+ sp_core::H256,
+ sp_runtime::traits::Hash,
sp_staking::SessionIndex,
sp_std::collections::btree_set::BTreeSet,
+ sp_std::vec,
+ sp_std::vec::Vec,
+ tp_bridge::{Command, DeliverMessage, Message, ValidateMessage},
};
+/// Utils needed to generate/verify merkle roots/proofs inside this pallet.
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct EraRewardsUtils {
+ pub rewards_merkle_root: H256,
+ pub leaves: Vec,
+ pub leaf_index: Option,
+ pub total_points: u128,
+}
+
#[frame_support::pallet]
pub mod pallet {
+ pub use crate::weights::WeightInfo;
use {
- frame_support::pallet_prelude::*, sp_std::collections::btree_map::BTreeMap,
+ super::*, frame_support::pallet_prelude::*, sp_std::collections::btree_map::BTreeMap,
tp_traits::EraIndexProvider,
};
@@ -64,6 +87,26 @@ pub mod pallet {
/// The amount of era points given by dispute voting on a candidate.
#[pallet::constant]
type DisputeStatementPoints: Get;
+
+ /// Provider to know how may tokens were inflated (added) in a specific era.
+ type EraInflationProvider: Get;
+
+ /// Provider to retrieve the current block timestamp.
+ type TimestampProvider: Get;
+
+ /// Hashing tool used to generate/verify merkle roots and proofs.
+ type Hashing: Hash