use revm::primitives::{Address, U256};
#[derive(Debug, Clone)]
pub struct Validator {
pub stake: U256,
pub accumulated_reward_per_token: U256,
pub commission: U256,
pub secp_pubkey: [u8; 33],
pub bls_pubkey: [u8; 48],
pub auth_address: Address,
pub flags: u64,
pub unclaimed_rewards: U256,
}
impl Default for Validator {
fn default() -> Self {
Self {
stake: U256::ZERO,
accumulated_reward_per_token: U256::ZERO,
commission: U256::ZERO,
secp_pubkey: [0u8; 33],
bls_pubkey: [0u8; 48],
auth_address: Address::ZERO,
flags: 0,
unclaimed_rewards: U256::ZERO,
}
}
}
pub mod validator_flags {
pub const OK: u64 = 0;
pub const STAKE_TOO_LOW: u64 = 1 << 0;
pub const WITHDRAWN: u64 = 1 << 1;
pub const DOUBLE_SIGN: u64 = 1 << 2;
}
#[derive(Debug, Clone, Default)]
pub struct Delegator {
pub stake: U256,
pub accumulated_reward_per_token: U256,
pub rewards: U256,
pub delta_stake: U256,
pub next_delta_stake: U256,
pub delta_epoch: u64,
pub next_delta_epoch: u64,
}
#[derive(Debug, Clone, Default)]
pub struct ListNode {
pub inext: u64,
pub iprev: u64,
pub anext: Address,
pub aprev: Address,
}
impl ListNode {
pub const SENTINEL_VAL_ID: u64 = u64::MAX;
pub const SENTINEL_ADDRESS: Address = Address::new([0xFF; 20]);
pub fn from_slots(slot6: [u8; 32], slot7: [u8; 32]) -> Self {
let inext = u64::from_be_bytes(slot6[0..8].try_into().unwrap());
let iprev = u64::from_be_bytes(slot6[8..16].try_into().unwrap());
let mut anext_bytes = [0u8; 20];
anext_bytes[..16].copy_from_slice(&slot6[16..32]);
anext_bytes[16..].copy_from_slice(&slot7[..4]);
let anext = Address::from(anext_bytes);
let aprev = Address::from_slice(&slot7[4..24]);
Self { inext, iprev, anext, aprev }
}
pub fn to_slots(&self) -> ([u8; 32], [u8; 32]) {
let mut slot6 = [0u8; 32];
let mut slot7 = [0u8; 32];
slot6[0..8].copy_from_slice(&self.inext.to_be_bytes());
slot6[8..16].copy_from_slice(&self.iprev.to_be_bytes());
slot6[16..32].copy_from_slice(&self.anext.as_slice()[..16]);
slot7[0..4].copy_from_slice(&self.anext.as_slice()[16..20]);
slot7[4..24].copy_from_slice(self.aprev.as_slice());
(slot6, slot7)
}
}
#[derive(Debug, Clone, Default)]
pub struct RefCountedAccumulator {
pub value: U256,
pub refcount: u64,
}
#[derive(Debug, Clone, Default)]
pub struct WithdrawalRequest {
pub amount: U256,
pub accumulator: U256,
pub epoch: u64,
}
#[derive(Debug, Clone, Default)]
pub struct EpochInfo {
pub epoch: u64,
pub in_delay_period: bool,
}
#[derive(Debug, Clone, Default)]
pub struct ConsensusView {
pub stake: U256,
pub commission: U256,
}
impl Validator {
pub fn exists(&self) -> bool {
self.auth_address != Address::ZERO
}
pub const fn has_flag(&self, flag: u64) -> bool {
self.flags & flag != 0
}
}
impl Delegator {
pub fn exists(&self) -> bool {
self.stake != U256::ZERO
|| self.delta_stake != U256::ZERO
|| self.next_delta_stake != U256::ZERO
}
#[allow(clippy::missing_const_for_fn)]
pub fn total_stake(&self) -> U256 {
self.stake.saturating_add(self.delta_stake).saturating_add(self.next_delta_stake)
}
}
impl WithdrawalRequest {
pub fn exists(&self) -> bool {
self.amount != U256::ZERO
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_validator_exists() {
let mut validator = Validator::default();
assert!(!validator.exists());
validator.auth_address = Address::new([0x11; 20]);
assert!(validator.exists());
}
#[test]
fn test_validator_flags() {
let mut validator = Validator::default();
assert!(!validator.has_flag(validator_flags::STAKE_TOO_LOW));
validator.flags = validator_flags::STAKE_TOO_LOW;
assert!(validator.has_flag(validator_flags::STAKE_TOO_LOW));
assert!(!validator.has_flag(validator_flags::WITHDRAWN));
assert!(!validator.has_flag(validator_flags::DOUBLE_SIGN));
validator.flags = validator_flags::STAKE_TOO_LOW | validator_flags::DOUBLE_SIGN;
assert!(validator.has_flag(validator_flags::STAKE_TOO_LOW));
assert!(!validator.has_flag(validator_flags::WITHDRAWN));
assert!(validator.has_flag(validator_flags::DOUBLE_SIGN));
}
#[test]
fn test_list_node_roundtrip() {
let node = ListNode {
inext: 42,
iprev: ListNode::SENTINEL_VAL_ID,
anext: Address::new([0x11; 20]),
aprev: ListNode::SENTINEL_ADDRESS,
};
let (slot6, slot7) = node.to_slots();
let decoded = ListNode::from_slots(slot6, slot7);
assert_eq!(decoded.inext, node.inext);
assert_eq!(decoded.iprev, node.iprev);
assert_eq!(decoded.anext, node.anext);
assert_eq!(decoded.aprev, node.aprev);
}
#[test]
fn test_list_node_empty_roundtrip() {
let node = ListNode::default();
let (slot6, slot7) = node.to_slots();
let decoded = ListNode::from_slots(slot6, slot7);
assert_eq!(decoded.inext, 0);
assert_eq!(decoded.iprev, 0);
assert_eq!(decoded.anext, Address::ZERO);
assert_eq!(decoded.aprev, Address::ZERO);
}
#[test]
fn test_delegator_total_stake() {
let delegator = Delegator {
stake: U256::from(100),
delta_stake: U256::from(50),
next_delta_stake: U256::from(25),
..Default::default()
};
assert_eq!(delegator.total_stake(), U256::from(175));
}
}