Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
304 changes: 301 additions & 3 deletions Cargo.lock

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ members = [
"modules/ismp/clients/arbitrum",
"modules/ismp/clients/optimism",
"modules/ismp/clients/bsc",
"modules/ismp/clients/pharos",
"modules/ismp/clients/grandpa",
"modules/ismp/testsuite",
"modules/ismp/clients/ismp-arbitrum",
Expand All @@ -59,6 +60,9 @@ members = [
"modules/consensus/tendermint/prover",
"modules/consensus/tendermint/primitives",
"modules/consensus/tendermint/ics23-primitives",
"modules/consensus/pharos/primitives",
"modules/consensus/pharos/verifier",
"modules/consensus/pharos/prover",
"modules/trees/ethereum",
"modules/pallets/mmr",
"modules/pallets/mmr/primitives",
Expand All @@ -68,6 +72,7 @@ members = [
"modules/ismp/state-machines/evm",
"modules/ismp/state-machines/substrate",
"modules/ismp/state-machines/hyperbridge",
"modules/ismp/state-machines/pharos",
"modules/pallets/consensus-incentives",
"modules/pallets/messaging-fees",

Expand Down Expand Up @@ -117,6 +122,7 @@ members = [
"tesseract/consensus/relayer",
"tesseract/consensus/polygon",
"tesseract/consensus/tendermint",
"tesseract/consensus/pharos",


# Airdrop
Expand Down Expand Up @@ -264,9 +270,13 @@ tendermint-verifier = { path = "./modules/consensus/tendermint/verifier", defaul
tendermint-primitives = { path = "./modules/consensus/tendermint/primitives", default-features = false }
tendermint-prover = { path = "./modules/consensus/tendermint/prover", default-features = false }
tendermint-ics23-primitives = { path = "./modules/consensus/tendermint/ics23-primitives", default-features = false }
pharos-primitives = { path = "./modules/consensus/pharos/primitives", default-features = false }
pharos-verifier = { path = "./modules/consensus/pharos/verifier", default-features = false }
pharos-prover = { path = "./modules/consensus/pharos/prover", default-features = false }

# consensus clients
ismp-bsc = { path = "./modules/ismp/clients/bsc", default-features = false }
ismp-pharos = { path = "./modules/ismp/clients/pharos", default-features = false }
ismp-sync-committee = { path = "./modules/ismp/clients/sync-committee", default-features = false }
arbitrum-verifier = { path = "./modules/ismp/clients/arbitrum", default-features = false }
op-verifier = { path = "./modules/ismp/clients/optimism", default-features = false }
Expand All @@ -277,6 +287,7 @@ ismp-tendermint = { path = "modules/ismp/clients/tendermint", default-features =

# state machine clients
evm-state-machine = { path = "./modules/ismp/state-machines/evm", default-features = false }
pharos-state-machine = { path = "./modules/ismp/state-machines/pharos", default-features = false }
hyperbridge-client-machine = { path = "modules/ismp/state-machines/hyperbridge", default-features = false }

# ismp modules
Expand Down Expand Up @@ -333,6 +344,7 @@ tesseract-grandpa = { path = "tesseract/consensus/grandpa" }
tesseract-consensus = { path = "tesseract/consensus/relayer" }
tesseract-polygon = { path = "tesseract/consensus/polygon" }
tesseract-tendermint = { path = "tesseract/consensus/tendermint" }
tesseract-pharos = { path = "tesseract/consensus/pharos" }


[workspace.dependencies.codec]
Expand Down Expand Up @@ -383,6 +395,15 @@ version = "1.1.2"
default-features = false
features = ["rlp"]

[workspace.dependencies.alloy-provider]
version = "~1.0"
default-features = false
features = ["reqwest", "reqwest-default-tls"]

[workspace.dependencies.alloy-eips]
version = "~1.3"
default-features = false

[workspace.dependencies.scale-info]
version = "2.1.1"
default-features = false
Expand Down
6 changes: 2 additions & 4 deletions modules/consensus/bsc/verifier/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,9 @@ primitive-types = { workspace = true }
codec = { workspace = true }
ismp = { workspace = true, default-features = false }
geth-primitives = { workspace = true, default-features = false }
sync-committee-verifier = { workspace = true, default-features = false }
crypto-utils = { workspace = true, default-features = false }
sync-committee-primitives = { workspace = true, default-features = false }
bls = { workspace = true }
ark-ec = { workspace = true }
ssz-rs = { git = "https://github.com/polytope-labs/ssz-rs", branch = "main", default-features = false }

[dependencies.polkadot-sdk]
Expand All @@ -38,9 +37,8 @@ std = [
"alloy-primitives/std",
"alloy-rlp/std",
"bls/std",
"sync-committee-verifier/std",
"crypto-utils/std",
"sync-committee-primitives/std",
"geth-primitives/std",
"ark-ec/std",
"ssz-rs/std",
]
12 changes: 1 addition & 11 deletions modules/consensus/bsc/verifier/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,13 @@ use polkadot_sdk::*;

use alloc::vec::Vec;
use anyhow::anyhow;
use bls::{point_to_pubkey, types::G1ProjectivePoint};
use crypto_utils::aggregate_public_keys;
use geth_primitives::{CodecHeader, Header};
use ismp::messaging::Keccak256;
use primitives::{parse_extra, BscClientUpdate, Config, VALIDATOR_BIT_SET_SIZE};
use sp_core::H256;
use ssz_rs::{Bitvector, Deserialize};
use sync_committee_primitives::constants::BlsPublicKey;
use sync_committee_verifier::crypto::pubkey_to_projective;

pub mod primitives;

Expand Down Expand Up @@ -164,12 +163,3 @@ pub fn verify_bsc_header<H: Keccak256, C: Config>(
next_validators: next_validator_addresses,
})
}

pub fn aggregate_public_keys(keys: &[BlsPublicKey]) -> Vec<u8> {
let aggregate = keys
.into_iter()
.filter_map(|key| pubkey_to_projective(key).ok())
.fold(G1ProjectivePoint::default(), |acc, next| acc + next);

point_to_pubkey(aggregate.into())
}
33 changes: 33 additions & 0 deletions modules/consensus/pharos/primitives/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
[package]
name = "pharos-primitives"
version = "0.1.0"
edition = "2021"
description = "Primitive types for Pharos consensus verifier"
authors = ["Polytope Labs <hello@polytope.technology>"]
publish = false

[dependencies]
codec = { workspace = true, features = ["derive"] }
alloy-primitives = { workspace = true }
crypto-utils = { workspace = true, default-features = false }
primitive-types = { workspace = true, features = ["serde_no_std", "impl-codec"] }
hex-literal = { workspace = true }
serde = { workspace = true, optional = true, features = ["derive"] }
sp-io = { workspace = true, default-features = false }
anyhow = { workspace = true, default-features = false }
geth-primitives = { workspace = true, default-features = false }
ismp = { workspace = true, default-features = false }

[features]
default = ["std"]
std = [
"codec/std",
"alloy-primitives/std",
"crypto-utils/std",
"primitive-types/std",
"anyhow/std",
"sp-io/std",
"serde",
"geth-primitives/std",
"ismp/std",
]
122 changes: 122 additions & 0 deletions modules/consensus/pharos/primitives/src/constants.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// Copyright (C) Polytope Labs Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Constants and configuration for Pharos consensus.

use alloy_primitives::Address;

/// Re-export BLS types from crypto-utils
pub use crypto_utils::{
BlsPublicKey, BlsSignature, BLS_PUBLIC_KEY_BYTES_LEN, BLS_SIGNATURE_BYTES_LEN,
};

/// The staking contract address where validator set is stored.
/// Address: 0x4100000000000000000000000000000000000000
pub const STAKING_CONTRACT_ADDRESS: Address =
Address::new([0x41, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);

/// Consensus ID for Pharos network
pub const PHAROS_CONSENSUS_ID: [u8; 4] = *b"PHAR";

/// Mainnet epoch length in seconds (4 hours)
pub const MAINNET_EPOCH_LENGTH_SECS: u64 = 4 * 60 * 60; // 14400 seconds

/// Testnet (Atlantic) epoch length in seconds (~93.8 minutes)
pub const TESTNET_EPOCH_LENGTH_SECS: u64 = 5628;

/// Pharos Mainnet chain ID
pub const PHAROS_MAINNET_CHAIN_ID: u32 = 688600;

/// Pharos Atlantic Testnet chain ID
pub const PHAROS_ATLANTIC_CHAIN_ID: u32 = 688689;

/// Default withdraw window in epochs from the Pharos staking contract.
pub const DEFAULT_WITHDRAW_WINDOW_EPOCHS: u64 = 84;

/// Configuration trait for Pharos network parameters.
pub trait Config: Clone + Send + Sync {
/// The epoch length in seconds
const EPOCH_LENGTH_SECS: u64;

/// The epoch length in blocks (derived from epoch length and block time)
const EPOCH_LENGTH_BLOCKS: u64;

/// The chain ID for this network
const CHAIN_ID: u64;

/// Network identifier
const ID: [u8; 4];

/// The unstaking period in seconds (withdraw_window_epochs × epoch_length_secs).
/// Defaults to `DEFAULT_WITHDRAW_WINDOW_EPOCHS × EPOCH_LENGTH_SECS`.
const UNBONDING_PERIOD: u64 = DEFAULT_WITHDRAW_WINDOW_EPOCHS * Self::EPOCH_LENGTH_SECS;

/// Calculate the epoch number for a given block number
fn compute_epoch(block_number: u64) -> u64 {
block_number / Self::EPOCH_LENGTH_BLOCKS
}

/// Check if a block is an epoch boundary block (last block of an epoch).
///
/// The epoch boundary is defined as the last block of an epoch, i.e.,
/// `(block_number + 1) % epoch_length == 0`.
///
/// At epoch boundaries, the validator set for the next epoch is finalized
fn is_epoch_boundary(block_number: u64) -> bool {
(block_number + 1) % Self::EPOCH_LENGTH_BLOCKS == 0
}

/// Get the first block number of the next epoch
fn next_epoch_start(current_block: u64) -> u64 {
let current_epoch = Self::compute_epoch(current_block);
(current_epoch + 1) * Self::EPOCH_LENGTH_BLOCKS
}
}

/// Pharos Mainnet configuration
#[derive(Clone, Default, Debug)]
pub struct Mainnet;

impl Config for Mainnet {
/// 4 hours epoch length
const EPOCH_LENGTH_SECS: u64 = MAINNET_EPOCH_LENGTH_SECS;

/// With ~1 second finality (sub-second), assuming 1 block per second
/// 4 hours = 14400 blocks
const EPOCH_LENGTH_BLOCKS: u64 = 14400;

/// Mainnet chain ID - TBD
/// Placeholder based on testnet pattern
const CHAIN_ID: u64 = 688600;

const ID: [u8; 4] = PHAROS_CONSENSUS_ID;
}

/// Pharos Testnet configuration
#[derive(Clone, Default, Debug)]
pub struct Testnet;

impl Config for Testnet {
/// ~93.8 minutes epoch length
const EPOCH_LENGTH_SECS: u64 = TESTNET_EPOCH_LENGTH_SECS;

/// Updated to match on-chain value from staking contract slot 5 (February 2026)
const EPOCH_LENGTH_BLOCKS: u64 = 5628;

/// Pharos Testnet chain ID
const CHAIN_ID: u64 = 688689;

const ID: [u8; 4] = PHAROS_CONSENSUS_ID;
}
24 changes: 24 additions & 0 deletions modules/consensus/pharos/primitives/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (C) Polytope Labs Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#![cfg_attr(not(feature = "std"), no_std)]

extern crate alloc;

pub mod constants;
pub mod spv;
pub mod types;

pub use constants::*;
pub use types::*;
Loading
Loading