Skip to content

Commit 8ccc5a7

Browse files
committed
more progress on runtime apis
1 parent b79e861 commit 8ccc5a7

File tree

10 files changed

+160
-93
lines changed

10 files changed

+160
-93
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pallets/external-validators-rewards/runtime-api/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ workspace = true
1414

1515
[dependencies]
1616
parity-scale-codec = { workspace = true }
17+
snowbridge-outbound-queue-merkle-tree = { workspace = true }
1718
sp-api = { workspace = true }
1819
sp-core = { workspace = true }
1920

2021
[features]
2122
default = [ "std" ]
2223
std = [
2324
"parity-scale-codec/std",
25+
"snowbridge-outbound-queue-merkle-tree/std",
2426
"sp-api/std",
25-
"sp-core/std"
27+
"sp-core/std",
2628
]

pallets/external-validators-rewards/runtime-api/src/lib.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@
1818
1919
#![cfg_attr(not(feature = "std"), no_std)]
2020

21+
use snowbridge_outbound_queue_merkle_tree::MerkleProof;
22+
2123
sp_api::decl_runtime_apis! {
22-
pub trait ExternalValidatorsRewardsApi<EraIndex>
24+
pub trait ExternalValidatorsRewardsApi<AccountId, EraIndex>
2325
where
26+
AccountId: parity_scale_codec::Codec,
2427
EraIndex: parity_scale_codec::Codec,
2528
{
26-
fn generate_rewards_merkle_proof(era_index: EraIndex) -> sp_core::H256;
29+
fn generate_rewards_merkle_proof(account_id: AccountId, era_index: EraIndex) -> Option<MerkleProof>;
30+
fn verify_rewards_merkle_proof(merkle_proof: MerkleProof) -> bool;
2731
}
28-
}
32+
}

pallets/external-validators-rewards/src/lib.rs

Lines changed: 90 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -33,21 +33,20 @@ use {
3333
polkadot_primitives::ValidatorIndex,
3434
runtime_parachains::session_info,
3535
snowbridge_core::ChannelId,
36-
snowbridge_outbound_queue_merkle_tree::merkle_root,
36+
snowbridge_outbound_queue_merkle_tree::{merkle_proof, merkle_root, verify_proof, MerkleProof},
3737
sp_core::H256,
38-
sp_runtime::{DigestItem, traits::Hash},
38+
sp_runtime::traits::Hash,
3939
sp_staking::SessionIndex,
4040
sp_std::collections::btree_set::BTreeSet,
4141
sp_std::vec,
4242
sp_std::vec::Vec,
43-
tp_bridge::{Command, Message, ValidateMessage, DeliverMessage},
43+
tp_bridge::{Command, DeliverMessage, Message, ValidateMessage},
4444
};
4545

4646
#[frame_support::pallet]
4747
pub mod pallet {
4848
use {
49-
super::*,
50-
frame_support::pallet_prelude::*, sp_std::collections::btree_map::BTreeMap,
49+
super::*, frame_support::pallet_prelude::*, sp_std::collections::btree_map::BTreeMap,
5150
tp_traits::EraIndexProvider,
5251
};
5352

@@ -123,6 +122,63 @@ pub mod pallet {
123122
}
124123
})
125124
}
125+
126+
pub fn generate_era_rewards_utils(
127+
era_index: EraIndex,
128+
maybe_account_id_check: Option<T::AccountId>,
129+
) -> Option<(H256, Vec<H256>, Option<u64>, u128)> {
130+
let era_rewards = RewardPointsForEra::<T>::get(&era_index);
131+
let total_points: u128 = era_rewards.total as u128;
132+
let mut leaves = Vec::with_capacity(era_rewards.individual.len());
133+
let mut leaf_index = None;
134+
135+
for (index, (account_id, reward_points)) in era_rewards.individual.iter().enumerate() {
136+
let encoded = (account_id, reward_points).encode();
137+
let hashed = <T as Config>::Hashing::hash(&encoded);
138+
leaves.push(hashed);
139+
140+
if let Some(ref check_account_id) = maybe_account_id_check {
141+
if account_id == check_account_id {
142+
leaf_index = Some(index as u64);
143+
}
144+
}
145+
}
146+
147+
// If a specific account is checked but not found, return None
148+
if maybe_account_id_check.is_some() && leaf_index.is_none() {
149+
log::error!(
150+
target: "ext_validators_rewards",
151+
"AccountId {:?} not found for era {:?}!",
152+
maybe_account_id_check,
153+
era_index
154+
);
155+
return None;
156+
}
157+
158+
let rewards_merkle_root =
159+
merkle_root::<<T as Config>::Hashing, _>(leaves.iter().cloned());
160+
Some((rewards_merkle_root, leaves, leaf_index, total_points))
161+
}
162+
163+
pub fn generate_rewards_merkle_proof(
164+
account_id: T::AccountId,
165+
era_index: EraIndex,
166+
) -> Option<MerkleProof> {
167+
let (_, leaves, leaf_index, _) =
168+
Self::generate_era_rewards_utils(era_index, Some(account_id))?;
169+
leaf_index
170+
.map(|index| merkle_proof::<<T as Config>::Hashing, _>(leaves.into_iter(), index))
171+
}
172+
173+
pub fn verify_rewards_merkle_proof(merkle_proof: MerkleProof) -> bool {
174+
verify_proof::<<T as Config>::Hashing, _, _>(
175+
&merkle_proof.root,
176+
merkle_proof.proof,
177+
merkle_proof.number_of_leaves,
178+
merkle_proof.leaf_index,
179+
merkle_proof.leaf,
180+
)
181+
}
126182
}
127183

128184
impl<T: Config> tp_traits::OnEraStart for Pallet<T> {
@@ -137,44 +193,36 @@ pub mod pallet {
137193

138194
impl<T: Config> tp_traits::OnEraEnd for Pallet<T> {
139195
fn on_era_end(era_index: EraIndex) {
140-
let era_rewards = RewardPointsForEra::<T>::get(&era_index);
141-
let total_points: u128 = era_rewards.total as u128;
142-
let mut rewards_info_to_merkelize: Vec<H256> = vec![];
143-
144-
for (account_id, reward_points) in era_rewards.individual {
145-
let encoded = (account_id, reward_points).encode();
146-
let hashed = <T as Config>::Hashing::hash(&encoded);
147-
rewards_info_to_merkelize.push(hashed);
148-
}
149-
150-
let rewards_merkle_root = merkle_root::<<T as Config>::Hashing, _>(rewards_info_to_merkelize.into_iter());
151-
152-
let command = Command::ReportRewards {
153-
timestamp: T::TimestampProvider::get(),
154-
era_index,
155-
total_points,
156-
// TODO: manage this in a proper way.
157-
tokens_inflated: 0u128,
158-
rewards_merkle_root
159-
};
160-
161-
let channel_id: ChannelId = snowbridge_core::PRIMARY_GOVERNANCE_CHANNEL;
162-
163-
let outbound_message = Message {
164-
id: None,
165-
channel_id,
166-
command,
167-
};
168-
169-
// Validate and deliver the message
170-
match T::ValidateMessage::validate(&outbound_message) {
171-
Ok((ticket, _fee)) => {
172-
if let Err(err) = T::OutboundQueue::deliver(ticket) {
173-
log::error!(target: "xcm::ethereum_blob_exporter", "OutboundQueue delivery of message failed. {err:?}");
196+
if let Some((rewards_merkle_root, _, _, total_points)) =
197+
Self::generate_era_rewards_utils(era_index, None)
198+
{
199+
let command = Command::ReportRewards {
200+
timestamp: T::TimestampProvider::get(),
201+
era_index,
202+
total_points,
203+
// TODO: manage this in a proper way.
204+
tokens_inflated: 0u128,
205+
rewards_merkle_root,
206+
};
207+
208+
let channel_id: ChannelId = snowbridge_core::PRIMARY_GOVERNANCE_CHANNEL;
209+
210+
let outbound_message = Message {
211+
id: None,
212+
channel_id,
213+
command,
214+
};
215+
216+
// Validate and deliver the message
217+
match T::ValidateMessage::validate(&outbound_message) {
218+
Ok((ticket, _fee)) => {
219+
if let Err(err) = T::OutboundQueue::deliver(ticket) {
220+
log::error!(target: "xcm::ethereum_blob_exporter", "OutboundQueue delivery of message failed. {err:?}");
221+
}
222+
}
223+
Err(err) => {
224+
log::error!(target: "xcm::ethereum_blob_exporter", "OutboundQueue validation of message failed. {err:?}");
174225
}
175-
},
176-
Err(err) => {
177-
log::error!(target: "xcm::ethereum_blob_exporter", "OutboundQueue validation of message failed. {err:?}");
178226
}
179227
}
180228
}

primitives/bridge/src/custom_do_process_message.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ impl ConstantGasMeter {
151151
fn maximum_dispatch_gas_used_at_most(command: &Command) -> u64 {
152152
match command {
153153
Command::Test { .. } => 60_000,
154-
Command::ReportRewards { .. } => 60_000
154+
Command::ReportRewards { .. } => 60_000,
155155
}
156156
}
157157
}

primitives/bridge/src/lib.rs

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,13 @@ pub enum Command {
6262
timestamp: u64,
6363
// index of the era we are sending info of
6464
era_index: u32,
65-
// total_points for the era
65+
// total_points for the era
6666
total_points: u128,
6767
// new tokens inflated during the era
6868
tokens_inflated: u128,
6969
// merkle root of vec![(validatorId, rewardPoints)]
70-
rewards_merkle_root: H256
71-
}
70+
rewards_merkle_root: H256,
71+
},
7272
}
7373

7474
impl Command {
@@ -86,14 +86,26 @@ impl Command {
8686
match self {
8787
Command::Test(payload) => {
8888
ethabi::encode(&[Token::Tuple(vec![Token::Bytes(payload.clone())])])
89-
},
90-
Command::ReportRewards { timestamp, era_index, total_points, tokens_inflated, rewards_merkle_root } => {
89+
}
90+
Command::ReportRewards {
91+
timestamp,
92+
era_index,
93+
total_points,
94+
tokens_inflated,
95+
rewards_merkle_root,
96+
} => {
9197
let timestamp_token = Token::Uint(U256::from(*timestamp));
9298
let era_index_token = Token::Uint(U256::from(*era_index));
9399
let total_points_token = Token::Uint(U256::from(*total_points));
94100
let tokens_inflated_token = Token::Uint(U256::from(*tokens_inflated));
95101
let rewards_mr_token = Token::FixedBytes(rewards_merkle_root.0.to_vec());
96-
ethabi::encode(&[Token::Tuple(vec![timestamp_token, era_index_token, total_points_token, tokens_inflated_token, rewards_mr_token])])
102+
ethabi::encode(&[Token::Tuple(vec![
103+
timestamp_token,
104+
era_index_token,
105+
total_points_token,
106+
tokens_inflated_token,
107+
rewards_mr_token,
108+
])])
97109
}
98110
}
99111
}
@@ -231,4 +243,3 @@ pub trait DeliverMessage {
231243

232244
fn deliver(ticket: Self::Ticket) -> Result<H256, SendError>;
233245
}
234-

solo-chains/runtime/dancelight/src/lib.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ use {
7878
scale_info::TypeInfo,
7979
serde::{Deserialize, Serialize},
8080
snowbridge_core::ChannelId,
81+
snowbridge_pallet_outbound_queue::MerkleProof,
8182
sp_core::{storage::well_known_keys as StorageWellKnownKeys, Get},
8283
sp_genesis_builder::PresetId,
8384
sp_runtime::{
@@ -2706,13 +2707,16 @@ sp_api::impl_runtime_apis! {
27062707
}
27072708
}
27082709

2709-
impl pallet_external_validators_rewards_runtime_api::ExternalValidatorsRewardsApi<Block, EraIndex> for Runtime
2710+
impl pallet_external_validators_rewards_runtime_api::ExternalValidatorsRewardsApi<Block, AccountId, EraIndex> for Runtime
27102711
where
2711-
EraIndex: parity_scale_codec::Codec,
2712+
EraIndex: parity_scale_codec::Codec,
27122713
{
2713-
fn generate_rewards_merkle_proof(era_index: EraIndex) -> H256 {
2714-
//ExternalValidatorsRewards::get_rewards_merkle_root_and_total_points(era_index).0
2715-
H256::default()
2714+
fn generate_rewards_merkle_proof(account_id: AccountId, era_index: EraIndex) -> Option<MerkleProof> {
2715+
ExternalValidatorsRewards::generate_rewards_merkle_proof(account_id, era_index)
2716+
}
2717+
2718+
fn verify_rewards_merkle_proof(merkle_proof: MerkleProof) -> bool {
2719+
ExternalValidatorsRewards::verify_rewards_merkle_proof(merkle_proof)
27162720
}
27172721
}
27182722

solo-chains/runtime/dancelight/src/tests/external_validators_tests.rs

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,17 @@
1818

1919
use {
2020
crate::{
21-
tests::common::*, EthereumSystem, ExternalValidators, ExternalValidatorsRewards, MaxExternalValidators, RuntimeEvent, SessionKeys, SessionsPerEra, System
22-
}, frame_support::{assert_ok, traits::fungible::Mutate}, pallet_external_validators::Forcing, parity_scale_codec::Encode,
23-
snowbridge_core::{Channel, PRIMARY_GOVERNANCE_CHANNEL},
24-
sp_core::H256, sp_io::hashing::twox_64, std::{collections::HashMap, ops::RangeInclusive}, tp_traits::OnEraEnd
21+
tests::common::*, EthereumSystem, ExternalValidators, ExternalValidatorsRewards,
22+
MaxExternalValidators, RuntimeEvent, SessionKeys, SessionsPerEra, System,
23+
},
24+
frame_support::{assert_ok, traits::fungible::Mutate},
25+
pallet_external_validators::Forcing,
26+
parity_scale_codec::Encode,
27+
snowbridge_core::{Channel, PRIMARY_GOVERNANCE_CHANNEL},
28+
sp_core::H256,
29+
sp_io::hashing::twox_64,
30+
std::{collections::HashMap, ops::RangeInclusive},
31+
tp_traits::OnEraEnd,
2532
};
2633

2734
fn assert_validators_do_not_change(
@@ -714,27 +721,35 @@ fn external_validators_rewards_sends_message_on_era_end() {
714721
combined_channel_id_key.extend_from_slice(PRIMARY_GOVERNANCE_CHANNEL.as_ref());
715722

716723
let mut full_storage_key = Vec::new();
717-
full_storage_key.extend_from_slice(&frame_support::storage::storage_prefix(b"EthereumSystem", b"Channels"));
724+
full_storage_key.extend_from_slice(&frame_support::storage::storage_prefix(
725+
b"EthereumSystem",
726+
b"Channels",
727+
));
718728
full_storage_key.extend_from_slice(&combined_channel_id_key);
719729

720730
let channel = Channel {
721731
agent_id: H256::default(),
722-
para_id: 1000u32.into()
732+
para_id: 1000u32.into(),
723733
};
724734

725735
frame_support::storage::unhashed::put(&full_storage_key, &channel);
726-
736+
727737
// This will call on_era_end for era 0
728738
run_to_session(sessions_per_era);
729739

730740
let outbound_msg_queue_event = System::events()
731-
.iter()
732-
.filter(|r| match r.event {
733-
RuntimeEvent::EthereumOutboundQueue(snowbridge_pallet_outbound_queue::Event::MessageQueued { .. }) => true,
734-
_ => false,
735-
})
736-
.count();
737-
738-
assert_eq!(outbound_msg_queue_event, 1, "MessageQueued event should be emitted");
741+
.iter()
742+
.filter(|r| match r.event {
743+
RuntimeEvent::EthereumOutboundQueue(
744+
snowbridge_pallet_outbound_queue::Event::MessageQueued { .. },
745+
) => true,
746+
_ => false,
747+
})
748+
.count();
749+
750+
assert_eq!(
751+
outbound_msg_queue_event, 1,
752+
"MessageQueued event should be emitted"
753+
);
739754
});
740755
}

test/suites/dev-tanssi-relay/rewards-mapping/test-runtime-api.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ describeSuite({
5353
title: "Should succeed calling runtime api",
5454
test: async function () {
5555

56-
await polkadotJs.call.externalValidatorsRewardsApi.generate_rewards_merkle_root(0);
56+
await polkadotJs.call.externalValidatorsRewardsApi.generate_rewards_merkle_proof(0);
5757

5858
},
5959
});

0 commit comments

Comments
 (0)