Start defining the coordinator

This commit is contained in:
Luke Parker 2023-04-15 17:38:47 -04:00
parent 51bf51ae1e
commit eafd054296
No known key found for this signature in database
7 changed files with 135 additions and 19 deletions

2
Cargo.lock generated
View file

@ -1305,10 +1305,12 @@ name = "coordinator"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"blake2", "blake2",
"log",
"modular-frost", "modular-frost",
"processor-messages", "processor-messages",
"rand_core 0.6.4", "rand_core 0.6.4",
"serai-client", "serai-client",
"serai-db",
"tokio", "tokio",
"tributary-chain", "tributary-chain",
] ]

View file

@ -14,13 +14,19 @@ all-features = true
rustdoc-args = ["--cfg", "docsrs"] rustdoc-args = ["--cfg", "docsrs"]
[dependencies] [dependencies]
log = "0.4"
blake2 = "0.10" blake2 = "0.10"
frost = { package = "modular-frost", path = "../crypto/frost" } frost = { package = "modular-frost", path = "../crypto/frost" }
serai-db = { path = "../common/db" }
processor-messages = { package = "processor-messages", path = "../processor/messages" } processor-messages = { package = "processor-messages", path = "../processor/messages" }
tributary = { package = "tributary-chain", path = "./tributary" } tributary = { package = "tributary-chain", path = "./tributary" }
serai-client = { path = "../substrate/client", features = ["serai"] }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
[dev-dependencies] [dev-dependencies]

View file

@ -1,7 +1,33 @@
#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unused_mut)]
use serai_db::Db;
use serai_client::Serai;
mod transaction; mod transaction;
mod substrate;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
async fn run<D: Db>(db: D, serai: Serai) {
let mut last_substrate_block = 0; // TODO: Load from DB
loop {
match substrate::handle_new_blocks(&serai, &mut last_substrate_block).await {
Ok(()) => {}
Err(e) => log::error!("couldn't communicate with serai node: {e}"),
}
// Handle all messages from tributaries
// Handle all messages from processors
}
}
#[tokio::main] #[tokio::main]
async fn main() {} async fn main() {
// Open the database
}

View file

@ -0,0 +1,52 @@
use serai_client::{SeraiError, Block, Serai};
async fn handle_block(serai: &Serai, block: Block) -> Result<Vec<()>, SeraiError> {
let hash = block.hash();
let mut actions = vec![];
// If a new validator set was activated, create tributary/inform processor to do a DKG
for new_set in serai.get_new_set_events(hash).await? {
todo!()
}
// If a key pair was confirmed, inform the processor
for key_gen in serai.get_key_gen_events(hash).await? {
todo!()
}
// If batch, tell processor of block acknowledged/burns
for new_set in serai.get_batch_events(hash).await? {
todo!()
}
Ok(actions)
}
pub(crate) async fn handle_new_blocks(
serai: &Serai,
last_substrate_block: &mut u64,
) -> Result<(), SeraiError> {
// Check if there's been a new Substrate block
let latest = serai.get_latest_block().await?;
let latest_number = latest.number();
if latest_number == *last_substrate_block {
return Ok(());
}
let mut latest = Some(latest);
for b in (*last_substrate_block + 1) ..= latest_number {
let actions = handle_block(
serai,
if b == latest_number {
latest.take().unwrap()
} else {
serai.get_block_by_number(b).await?.unwrap()
},
)
.await?;
// TODO: Handle actions, update the DB
*last_substrate_block += 1;
}
Ok(())
}

View file

@ -16,7 +16,7 @@ use subxt::{
extrinsic_params::{BaseExtrinsicParams, BaseExtrinsicParamsBuilder}, extrinsic_params::{BaseExtrinsicParams, BaseExtrinsicParamsBuilder},
}, },
tx::{Signer, Payload, TxClient}, tx::{Signer, Payload, TxClient},
rpc::types::ChainBlock, rpc::types::{ChainBlock, ChainBlockExtrinsic},
Config as SubxtConfig, OnlineClient, Config as SubxtConfig, OnlineClient,
}; };
@ -56,7 +56,32 @@ impl SubxtConfig for SeraiConfig {
type ExtrinsicParams = BaseExtrinsicParams<SeraiConfig, Tip>; type ExtrinsicParams = BaseExtrinsicParams<SeraiConfig, Tip>;
} }
pub type Block = ChainBlock<SeraiConfig>; #[derive(Debug)]
pub struct Block(ChainBlock<SeraiConfig>);
impl Block {
pub fn hash(&self) -> [u8; 32] {
self.0.header.hash().into()
}
pub fn number(&self) -> u64 {
self.0.header.number
}
pub fn header(&self) -> &Header {
&self.0.header
}
pub fn transactions(&self) -> &[ChainBlockExtrinsic] {
&self.0.extrinsics
}
}
impl Clone for Block {
fn clone(&self) -> Block {
Block(ChainBlock::<SeraiConfig> {
header: self.0.header.clone(),
extrinsics: self.0.extrinsics.clone(),
})
}
}
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum SeraiError { pub enum SeraiError {
@ -120,6 +145,19 @@ impl Serai {
Ok(self.0.rpc().finalized_head().await.map_err(SeraiError::RpcError)?.into()) Ok(self.0.rpc().finalized_head().await.map_err(SeraiError::RpcError)?.into())
} }
pub async fn get_latest_block(&self) -> Result<Block, SeraiError> {
Ok(Block(
self
.0
.rpc()
.block(Some(self.0.rpc().finalized_head().await.map_err(SeraiError::RpcError)?))
.await
.map_err(SeraiError::RpcError)?
.ok_or(SeraiError::InvalidNode)?
.block,
))
}
// There is no provided method for this // There is no provided method for this
// TODO: Add one to Serai // TODO: Add one to Serai
pub async fn is_finalized(&self, header: &Header) -> Result<Option<bool>, SeraiError> { pub async fn is_finalized(&self, header: &Header) -> Result<Option<bool>, SeraiError> {
@ -169,7 +207,7 @@ impl Serai {
return Ok(None); return Ok(None);
} }
Ok(Some(res.block)) Ok(Some(Block(res.block)))
} }
// Ideally, this would be get_block_hash, not get_block_by_number // Ideally, this would be get_block_hash, not get_block_by_number

View file

@ -2,7 +2,7 @@ use core::time::Duration;
use tokio::time::sleep; use tokio::time::sleep;
use serai_client::subxt::{config::Header, utils::Encoded}; use serai_client::subxt::utils::Encoded;
use crate::common::serai; use crate::common::serai;
@ -10,13 +10,8 @@ use crate::common::serai;
pub async fn publish_tx(tx: &Encoded) -> [u8; 32] { pub async fn publish_tx(tx: &Encoded) -> [u8; 32] {
let serai = serai().await; let serai = serai().await;
let mut latest = serai let mut latest =
.get_block(serai.get_latest_block_hash().await.unwrap()) serai.get_block(serai.get_latest_block_hash().await.unwrap()).await.unwrap().unwrap().number();
.await
.unwrap()
.unwrap()
.header
.number();
serai.publish(tx).await.unwrap(); serai.publish(tx).await.unwrap();
@ -42,9 +37,9 @@ pub async fn publish_tx(tx: &Encoded) -> [u8; 32] {
block.unwrap() block.unwrap()
}; };
for extrinsic in block.extrinsics { for transaction in block.transactions() {
if extrinsic.0 == tx.0[2 ..] { if transaction.0 == tx.0[2 ..] {
return block.header.hash().into(); return block.hash();
} }
} }
} }

View file

@ -10,7 +10,6 @@ use serai_client::{
primitives::{Session, ValidatorSet}, primitives::{Session, ValidatorSet},
ValidatorSetsEvent, ValidatorSetsEvent,
}, },
subxt::config::Header,
Serai, Serai,
}; };
@ -38,9 +37,7 @@ serai_test!(
// Make sure the genesis is as expected // Make sure the genesis is as expected
assert_eq!( assert_eq!(
serai serai
.get_new_set_events( .get_new_set_events(serai.get_block_by_number(0).await.unwrap().unwrap().hash())
serai.get_block_by_number(0).await.unwrap().unwrap().header.hash().into()
)
.await .await
.unwrap(), .unwrap(),
[BITCOIN_NET_ID, ETHEREUM_NET_ID, MONERO_NET_ID] [BITCOIN_NET_ID, ETHEREUM_NET_ID, MONERO_NET_ID]