diff --git a/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/types.rs b/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/types.rs index 39a65870c..ad10d0682 100644 --- a/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/types.rs +++ b/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/types.rs @@ -39,6 +39,13 @@ sol! { // Function from ValidatorManagement contract function getActiveValidators() external view returns (ValidatorConsensusInfo[] memory); + // Functions to get pending validators (now return full ValidatorConsensusInfo[]) + function getPendingActiveValidators() external view returns (ValidatorConsensusInfo[] memory); + function getPendingInactiveValidators() external view returns (ValidatorConsensusInfo[] memory); + + // Function to get total voting power directly from contract + function getTotalVotingPower() external view returns (uint256); + /// NewEpochEvent from Reconfiguration.sol /// Emitted when epoch transition completes with full validator set event NewEpochEvent( @@ -106,20 +113,40 @@ pub fn convert_validator_consensus_info( ) } -/// Convert array of ValidatorConsensusInfo to BCS-encoded ValidatorSet +/// Convert arrays of ValidatorConsensusInfo to BCS-encoded ValidatorSet /// Used by ValidatorSetFetcher to convert getActiveValidators() response -pub fn convert_active_validators_to_bcs(validators: &[ValidatorConsensusInfo]) -> Bytes { +/// +/// # Arguments +/// * `active_validators` - Active validators from getActiveValidators() +/// * `pending_active` - Validators pending activation (optional, from getCurValidatorConsensusInfos style query) +/// * `pending_inactive` - Validators pending deactivation (still in active set for this epoch) +pub fn convert_validators_to_bcs( + active_validators: &[ValidatorConsensusInfo], + pending_active: &[ValidatorConsensusInfo], + pending_inactive: &[ValidatorConsensusInfo], +) -> Bytes { + // Calculate total voting power from active validators (in Ether units) let total_voting_power: u128 = - validators.iter().map(|v| wei_to_ether(v.votingPower).to::()).sum(); + active_validators.iter().map(|v| wei_to_ether(v.votingPower).to::()).sum(); + + // Calculate total joining power from pending_active validators + let total_joining_power: u128 = + pending_active.iter().map(|v| wei_to_ether(v.votingPower).to::()).sum(); let gravity_validator_set = GravityValidatorSet { - active_validators: validators.iter().map(convert_validator_consensus_info).collect(), - pending_inactive: vec![], // Not returned by getActiveValidators() - pending_active: vec![], // Not returned by getActiveValidators() + active_validators: active_validators.iter().map(convert_validator_consensus_info).collect(), + pending_inactive: pending_inactive.iter().map(convert_validator_consensus_info).collect(), + pending_active: pending_active.iter().map(convert_validator_consensus_info).collect(), total_voting_power, - total_joining_power: 0, // Not returned by getActiveValidators() + total_joining_power, }; // Serialize to BCS format (gravity-aptos standard) bcs::to_bytes(&gravity_validator_set).expect("Failed to serialize validator set").into() } + +/// Legacy function for backward compatibility - only active validators +/// Used when we don't have pending validator info available +pub fn convert_active_validators_to_bcs(validators: &[ValidatorConsensusInfo]) -> Bytes { + convert_validators_to_bcs(validators, &[], &[]) +} \ No newline at end of file diff --git a/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/validator_set.rs b/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/validator_set.rs index 14316a075..457fcd99e 100644 --- a/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/validator_set.rs +++ b/crates/pipe-exec-layer-ext-v2/execute/src/onchain_config/validator_set.rs @@ -2,7 +2,10 @@ use super::{ base::{ConfigFetcher, OnchainConfigFetcher}, - types::{convert_active_validators_to_bcs, getActiveValidatorsCall}, + types::{ + convert_validators_to_bcs, getActiveValidatorsCall, getPendingActiveValidatorsCall, + getPendingInactiveValidatorsCall, + }, SYSTEM_CALLER, VALIDATOR_MANAGER_ADDR, }; use alloy_eips::BlockId; @@ -11,8 +14,6 @@ use alloy_rpc_types_eth::TransactionRequest; use alloy_sol_types::SolCall; use reth_rpc_eth_api::{helpers::EthCall, RpcTypes}; -// BCS for serialization - /// Fetcher for validator set information #[derive(Debug)] pub struct ValidatorSetFetcher<'a, EthApi> { @@ -35,24 +36,65 @@ where EthApi::NetworkTypes: RpcTypes, { fn fetch(&self, block_id: BlockId) -> Option { - // Use new getActiveValidators() function - let call = getActiveValidatorsCall {}; - let input: Bytes = call.abi_encode().into(); + // 1. Fetch active validators + let active_validators = { + let call = getActiveValidatorsCall {}; + let input: Bytes = call.abi_encode().into(); + let result = self + .base_fetcher + .eth_call(Self::caller_address(), Self::contract_address(), input, block_id) + .map_err(|e| { + tracing::warn!( + "Failed to fetch active validators at block {}: {:?}", + block_id, + e + ); + }) + .ok()?; + getActiveValidatorsCall::abi_decode_returns(&result) + .expect("Failed to decode getActiveValidators return value") + }; - let result = self - .base_fetcher - .eth_call(Self::caller_address(), Self::contract_address(), input, block_id) - .map_err(|e| { - tracing::warn!("Failed to fetch validator set at block {}: {:?}", block_id, e); - }) - .ok()?; + // 2. Fetch pending active validators + let pending_active = { + let call = getPendingActiveValidatorsCall {}; + let input: Bytes = call.abi_encode().into(); + let result = self + .base_fetcher + .eth_call(Self::caller_address(), Self::contract_address(), input, block_id) + .map_err(|e| { + tracing::warn!( + "Failed to fetch pending active validators at block {}: {:?}", + block_id, + e + ); + }) + .ok()?; + getPendingActiveValidatorsCall::abi_decode_returns(&result) + .expect("Failed to decode getPendingActiveValidators return value") + }; - // Decode the response as ValidatorConsensusInfo[] - let validators = getActiveValidatorsCall::abi_decode_returns(&result) - .expect("Failed to decode getActiveValidators return value"); + // 3. Fetch pending inactive validators + let pending_inactive = { + let call = getPendingInactiveValidatorsCall {}; + let input: Bytes = call.abi_encode().into(); + let result = self + .base_fetcher + .eth_call(Self::caller_address(), Self::contract_address(), input, block_id) + .map_err(|e| { + tracing::warn!( + "Failed to fetch pending inactive validators at block {}: {:?}", + block_id, + e + ); + }) + .ok()?; + getPendingInactiveValidatorsCall::abi_decode_returns(&result) + .expect("Failed to decode getPendingInactiveValidators return value") + }; - // Convert to BCS-encoded ValidatorSet format - Some(convert_active_validators_to_bcs(&validators)) + // Convert to BCS-encoded ValidatorSet format with all validator lists + Some(convert_validators_to_bcs(&active_validators, &pending_active, &pending_inactive)) } fn contract_address() -> Address {