espresso_types/v0/v0_3/
stake_table.rs

1use std::{collections::HashMap, sync::Arc};
2
3use alloy::primitives::{Address, U256};
4use async_lock::Mutex;
5use derive_more::derive::{From, Into};
6use hotshot::types::{BLSPubKey, SignatureKey};
7use hotshot_contract_adapter::sol_types::StakeTable::{
8    ConsensusKeysUpdated, Delegated, Undelegated, ValidatorExit, ValidatorRegistered,
9};
10use hotshot_types::{
11    data::EpochNumber, light_client::StateVerKey, network::PeerConfigKeys, PeerConfig,
12};
13use indexmap::IndexMap;
14use serde::{Deserialize, Serialize};
15use tokio::task::JoinHandle;
16
17use super::L1Client;
18use crate::{
19    traits::{MembershipPersistence, StateCatchup},
20    v0::ChainConfig,
21    SeqTypes,
22};
23
24/// Stake table holding all staking information (DA and non-DA stakers)
25#[derive(Debug, Clone, Serialize, Deserialize, From)]
26pub struct CombinedStakeTable(Vec<PeerConfigKeys<SeqTypes>>);
27
28#[derive(Clone, Debug, From, Into, Serialize, Deserialize, PartialEq, Eq)]
29/// NewType to disambiguate DA Membership
30pub struct DAMembers(pub Vec<PeerConfig<SeqTypes>>);
31
32#[derive(Clone, Debug, From, Into, Serialize, Deserialize, PartialEq, Eq)]
33/// NewType to disambiguate StakeTable
34pub struct StakeTable(pub Vec<PeerConfig<SeqTypes>>);
35
36#[derive(serde::Serialize, serde::Deserialize, Clone, Debug, PartialEq, Eq)]
37#[serde(bound(deserialize = ""))]
38pub struct Validator<KEY: SignatureKey> {
39    pub account: Address,
40    /// The peer's public key
41    pub stake_table_key: KEY,
42    /// the peer's state public key
43    pub state_ver_key: StateVerKey,
44    /// the peer's stake
45    pub stake: U256,
46    // commission
47    // TODO: MA commission is only valid from 0 to 10_000. Add newtype to enforce this.
48    pub commission: u16,
49    pub delegators: HashMap<Address, U256>,
50}
51
52#[derive(serde::Serialize, serde::Deserialize, std::hash::Hash, Clone, Debug, PartialEq, Eq)]
53#[serde(bound(deserialize = ""))]
54pub struct Delegator {
55    pub address: Address,
56    pub validator: Address,
57    pub stake: U256,
58}
59
60/// Type for holding result sets matching epochs to stake tables.
61pub type IndexedStake = (
62    EpochNumber,
63    IndexMap<alloy::primitives::Address, Validator<BLSPubKey>>,
64);
65
66#[derive(Clone, derive_more::derive::Debug)]
67pub struct StakeTableFetcher {
68    /// Peers for catching up the stake table
69    #[debug(skip)]
70    pub(crate) peers: Arc<dyn StateCatchup>,
71    /// Methods for stake table persistence.
72    #[debug(skip)]
73    pub(crate) persistence: Arc<Mutex<dyn MembershipPersistence>>,
74    /// L1 provider
75    pub(crate) l1_client: L1Client,
76    /// Verifiable `ChainConfig` holding contract address
77    pub(crate) chain_config: Arc<Mutex<ChainConfig>>,
78    pub(crate) update_task: Arc<StakeTableUpdateTask>,
79}
80
81#[derive(Debug, Default)]
82pub(crate) struct StakeTableUpdateTask(pub(crate) Mutex<Option<JoinHandle<()>>>);
83
84impl Drop for StakeTableUpdateTask {
85    fn drop(&mut self) {
86        if let Some(task) = self.0.get_mut().take() {
87            task.abort();
88        }
89    }
90}
91
92// (log block number, log index)
93pub type EventKey = (u64, u64);
94
95#[derive(Clone, derive_more::From, PartialEq, serde::Serialize, serde::Deserialize)]
96pub enum StakeTableEvent {
97    Register(ValidatorRegistered),
98    Deregister(ValidatorExit),
99    Delegate(Delegated),
100    Undelegate(Undelegated),
101    KeyUpdate(ConsensusKeysUpdated),
102}