diff --git a/coordinator/cosign/Cargo.toml b/coordinator/cosign/Cargo.toml index e42a846a..03cf337c 100644 --- a/coordinator/cosign/Cargo.toml +++ b/coordinator/cosign/Cargo.toml @@ -22,6 +22,7 @@ blake2 = { version = "0.11.0-rc.0", default-features = false, features = ["alloc borsh = { version = "1", default-features = false, features = ["std", "derive", "de_strict_order"] } serai-abi = { path = "../../substrate/abi", default-features = false, features = ["std"] } +serai-client-serai = { path = "../../substrate/client/serai", default-features = false } log = { version = "0.4", default-features = false, features = ["std"] } diff --git a/coordinator/cosign/src/intend.rs b/coordinator/cosign/src/intend.rs index ab6dcb99..644ff0c7 100644 --- a/coordinator/cosign/src/intend.rs +++ b/coordinator/cosign/src/intend.rs @@ -1,10 +1,13 @@ use core::future::Future; use std::{sync::Arc, collections::HashMap}; +use blake2::{Digest, Blake2b256}; + use serai_abi::primitives::{ balance::Amount, validator_sets::ExternalValidatorSet, address::SeraiAddress, + merkle::IncrementalUnbalancedMerkleTree, }; -use serai_client::Serai; +use serai_client_serai::Serai; use serai_db::*; use serai_task::ContinuallyRan; @@ -14,6 +17,7 @@ use crate::*; create_db!( CosignIntend { ScanCosignFrom: () -> u64, + BuildsUpon: () -> IncrementalUnbalancedMerkleTree, } ); @@ -40,9 +44,9 @@ async fn block_has_events_justifying_a_cosign( .await .map_err(|e| format!("{e:?}"))? .ok_or_else(|| "couldn't get block which should've been finalized".to_string())?; - let serai = serai.as_of(block.hash()); + let serai = serai.as_of(block.header.hash()).await.map_err(|e| format!("{e:?}"))?; - if !serai.validator_sets().key_gen_events().await.map_err(|e| format!("{e:?}"))?.is_empty() { + if !serai.validator_sets().set_keys_events().await.map_err(|e| format!("{e:?}"))?.is_empty() { return Ok((block, HasEvents::Notable)); } @@ -66,7 +70,7 @@ impl ContinuallyRan for CosignIntendTask { async move { let start_block_number = ScanCosignFrom::get(&self.db).unwrap_or(1); let latest_block_number = - self.serai.latest_finalized_block_number().await.map_err(|e| format!("{e:?}"))?.number(); + self.serai.latest_finalized_block_number().await.map_err(|e| format!("{e:?}"))?; for block_number in start_block_number ..= latest_block_number { let mut txn = self.db.txn(); @@ -76,26 +80,35 @@ impl ContinuallyRan for CosignIntendTask { .await .map_err(|e| format!("{e:?}"))?; + let mut builds_upon = + BuildsUpon::get(&txn).unwrap_or(IncrementalUnbalancedMerkleTree::new()); + // Check we are indexing a linear chain - if (block_number > 1) && - (<[u8; 32]>::from(block.header.parent_hash) != - SubstrateBlockHash::get(&txn, block_number - 1) - .expect("indexing a block but haven't indexed its parent")) + if block.header.builds_upon() != + builds_upon.clone().calculate(serai_abi::BLOCK_HEADER_BRANCH_TAG) { Err(format!( "node's block #{block_number} doesn't build upon the block #{} prior indexed", block_number - 1 ))?; } - let block_hash = block.hash(); + let block_hash = block.header.hash(); SubstrateBlockHash::set(&mut txn, block_number, &block_hash); + builds_upon.append( + serai_abi::BLOCK_HEADER_BRANCH_TAG, + Blake2b256::new_with_prefix([serai_abi::BLOCK_HEADER_LEAF_TAG]) + .chain_update(block_hash.0) + .finalize() + .into(), + ); + BuildsUpon::set(&mut txn, &builds_upon); let global_session_for_this_block = LatestGlobalSessionIntended::get(&txn); // If this is notable, it creates a new global session, which we index into the database // now if has_events == HasEvents::Notable { - let serai = self.serai.as_of(block_hash); + let serai = self.serai.as_of(block_hash).await.map_err(|e| format!("{e:?}"))?; let sets_and_keys = cosigning_sets(&serai).await?; let global_session = GlobalSession::id(sets_and_keys.iter().map(|(set, _key)| *set).collect()); @@ -109,7 +122,7 @@ impl ContinuallyRan for CosignIntendTask { keys.insert(set.network, SeraiAddress::from(*key)); let stake = serai .validator_sets() - .total_allocated_stake(set.network.into()) + .current_stake(set.network.into()) .await .map_err(|e| format!("{e:?}"))? .unwrap_or(Amount(0)) diff --git a/coordinator/cosign/src/lib.rs b/coordinator/cosign/src/lib.rs index 6abac9a0..c9d95f36 100644 --- a/coordinator/cosign/src/lib.rs +++ b/coordinator/cosign/src/lib.rs @@ -11,6 +11,7 @@ use borsh::{BorshSerialize, BorshDeserialize}; use serai_abi::{ primitives::{ + BlockHash, crypto::{Public, KeyPair}, network_id::ExternalNetworkId, validator_sets::{Session, ExternalValidatorSet}, @@ -18,7 +19,7 @@ use serai_abi::{ }, Block, }; -use serai_client::{Serai, TemporalSerai}; +use serai_client_serai::{Serai, TemporalSerai}; use serai_db::*; use serai_task::*; @@ -86,7 +87,7 @@ create_db! { // The following are populated by the intend task and used throughout the library // An index of Substrate blocks - SubstrateBlockHash: (block_number: u64) -> [u8; 32], + SubstrateBlockHash: (block_number: u64) -> BlockHash, // A mapping from a global session's ID to its relevant information. GlobalSessions: (global_session: [u8; 32]) -> GlobalSession, // The last block to be cosigned by a global session. @@ -124,7 +125,7 @@ async fn keys_for_network( network: ExternalNetworkId, ) -> Result, String> { let Some(latest_session) = - serai.validator_sets().session(network.into()).await.map_err(|e| format!("{e:?}"))? + serai.validator_sets().current_session(network.into()).await.map_err(|e| format!("{e:?}"))? else { // If this network hasn't had a session declared, move on return Ok(None); @@ -272,7 +273,10 @@ impl Cosigning { } /// Fetch a cosigned Substrate block's hash by its block number. - pub fn cosigned_block(getter: &impl Get, block_number: u64) -> Result, Faulted> { + pub fn cosigned_block( + getter: &impl Get, + block_number: u64, + ) -> Result, Faulted> { if block_number > Self::latest_cosigned_block_number(getter)? { return Ok(None); } diff --git a/coordinator/cosign/types/src/lib.rs b/coordinator/cosign/types/src/lib.rs index 62346166..3b6ab862 100644 --- a/coordinator/cosign/types/src/lib.rs +++ b/coordinator/cosign/types/src/lib.rs @@ -3,7 +3,7 @@ //! Types used when cosigning Serai. For more info, please see `serai-cosign`. use borsh::{BorshSerialize, BorshDeserialize}; -use serai_primitives::{crypto::Public, network_id::ExternalNetworkId}; +use serai_primitives::{BlockHash, crypto::Public, network_id::ExternalNetworkId}; /// The schnorrkel context to used when signing a cosign. pub const COSIGN_CONTEXT: &[u8] = b"/serai/coordinator/cosign"; @@ -16,7 +16,7 @@ pub struct CosignIntent { /// The number of the block to cosign. pub block_number: u64, /// The hash of the block to cosign. - pub block_hash: [u8; 32], + pub block_hash: BlockHash, /// If this cosign must be handled before further cosigns are. pub notable: bool, } @@ -29,7 +29,7 @@ pub struct Cosign { /// The number of the block to cosign. pub block_number: u64, /// The hash of the block to cosign. - pub block_hash: [u8; 32], + pub block_hash: BlockHash, /// The actual cosigner. pub cosigner: ExternalNetworkId, } diff --git a/substrate/primitives/src/address.rs b/substrate/primitives/src/address.rs index ed59c9bf..f54f9925 100644 --- a/substrate/primitives/src/address.rs +++ b/substrate/primitives/src/address.rs @@ -65,6 +65,17 @@ impl From for Public { } } +impl From for SeraiAddress { + fn from(key: crate::crypto::Public) -> Self { + Public::from(key).into() + } +} +impl From for crate::crypto::Public { + fn from(address: SeraiAddress) -> Self { + Public::from(address).into() + } +} + // We use Bech32m to encode addresses impl core::fmt::Display for SeraiAddress { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { diff --git a/substrate/primitives/src/merkle.rs b/substrate/primitives/src/merkle.rs index e133d2db..b63bc91c 100644 --- a/substrate/primitives/src/merkle.rs +++ b/substrate/primitives/src/merkle.rs @@ -73,7 +73,7 @@ impl UnbalancedMerkleTree { } /// An unbalanced Merkle tree which is incrementally created. -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug, BorshSerialize, BorshDeserialize)] #[cfg_attr( feature = "non_canonical_scale_derivations", derive(scale::Encode, scale::Decode, scale::DecodeWithMemTracking)