From a461431f15d0235b6cb1ad2b8392ff0b6ac2d414 Mon Sep 17 00:00:00 2001 From: 0xfirefist Date: Sat, 24 Feb 2024 01:14:58 +0530 Subject: [PATCH] finality checks in Fortuna --- fortuna/Cargo.lock | 2 +- fortuna/Cargo.toml | 2 +- fortuna/src/api.rs | 15 +++++++++------ fortuna/src/api/revelation.rs | 2 +- fortuna/src/chain/ethereum.rs | 28 +++++++++++++++++++--------- fortuna/src/chain/reader.rs | 24 ++++++++++++------------ fortuna/src/command/run.rs | 1 + fortuna/src/config.rs | 16 ++++++++++------ 8 files changed, 54 insertions(+), 36 deletions(-) diff --git a/fortuna/Cargo.lock b/fortuna/Cargo.lock index 81a150f13..d3a6884d1 100644 --- a/fortuna/Cargo.lock +++ b/fortuna/Cargo.lock @@ -1486,7 +1486,7 @@ dependencies = [ [[package]] name = "fortuna" -version = "3.2.4" +version = "3.3.4" dependencies = [ "anyhow", "axum", diff --git a/fortuna/Cargo.toml b/fortuna/Cargo.toml index c537a03ea..3532e0f93 100644 --- a/fortuna/Cargo.toml +++ b/fortuna/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "fortuna" -version = "3.2.4" +version = "3.3.4" edition = "2021" [dependencies] diff --git a/fortuna/src/api.rs b/fortuna/src/api.rs index 6a61da86f..723626ec3 100644 --- a/fortuna/src/api.rs +++ b/fortuna/src/api.rs @@ -1,9 +1,6 @@ use { crate::{ - chain::reader::{ - BlockNumber, - EntropyReader, - }, + chain::reader::EntropyReader, state::HashChainState, }, anyhow::Result, @@ -17,7 +14,10 @@ use { routing::get, Router, }, - ethers::core::types::Address, + ethers::{ + core::types::Address, + types::BlockNumber, + }, prometheus_client::{ encoding::EncodeLabelSet, metrics::{ @@ -80,7 +80,8 @@ pub struct BlockchainState { pub provider_address: Address, /// The server will wait for this many block confirmations of a request before revealing /// the random number. - pub reveal_delay_blocks: BlockNumber, + pub reveal_delay_blocks: u64, + pub recent_block_status: BlockNumber, } pub struct Metrics { @@ -242,6 +243,7 @@ mod test { contract: eth_read.clone(), provider_address: PROVIDER, reveal_delay_blocks: 1, + recent_block_status: BlockStatus::Latest, }; let avax_read = Arc::new(MockEntropyReader::with_requests(10, &[])); @@ -251,6 +253,7 @@ mod test { contract: avax_read.clone(), provider_address: PROVIDER, reveal_delay_blocks: 2, + recent_block_status: BlockStatus::Latest, }; let api_state = ApiState::new(&[ diff --git a/fortuna/src/api/revelation.rs b/fortuna/src/api/revelation.rs index ee3e371da..ecd1b7d1d 100644 --- a/fortuna/src/api/revelation.rs +++ b/fortuna/src/api/revelation.rs @@ -62,7 +62,7 @@ pub async fn revelation( let maybe_request_fut = state.contract.get_request(state.provider_address, sequence); - let current_block_number_fut = state.contract.get_block_number(); + let current_block_number_fut = state.contract.get_block_number(state.recent_block_status); let (maybe_request, current_block_number) = try_join!(maybe_request_fut, current_block_number_fut).map_err(|e| { diff --git a/fortuna/src/chain/ethereum.rs b/fortuna/src/chain/ethereum.rs index a167ca68d..75ad1dec7 100644 --- a/fortuna/src/chain/ethereum.rs +++ b/fortuna/src/chain/ethereum.rs @@ -1,16 +1,14 @@ use { crate::{ - chain::{ - reader, - reader::{ - BlockNumber, - EntropyReader, - }, + chain::reader::{ + self, + EntropyReader, }, config::EthereumConfig, }, anyhow::{ anyhow, + Error, Result, }, axum::async_trait, @@ -39,7 +37,10 @@ use { LocalWallet, Signer, }, - types::transaction::eip2718::TypedTransaction, + types::{ + transaction::eip2718::TypedTransaction, + BlockNumber, + }, }, sha3::{ Digest, @@ -209,7 +210,16 @@ impl EntropyReader for PythContract { } } - async fn get_block_number(&self) -> Result { - Ok(self.client().get_block_number().await?.as_u64()) + async fn get_block_number(&self, recent_block_status: BlockNumber) -> Result { + let block = self + .client() + .get_block(recent_block_status) + .await? + .ok_or_else(|| Error::msg("pending block confirmation"))?; + + Ok(block + .number + .ok_or_else(|| Error::msg("pending confirmation"))? + .as_u64()) } } diff --git a/fortuna/src/chain/reader.rs b/fortuna/src/chain/reader.rs index cf3922df3..6e051ead6 100644 --- a/fortuna/src/chain/reader.rs +++ b/fortuna/src/chain/reader.rs @@ -1,11 +1,12 @@ use { anyhow::Result, axum::async_trait, - ethers::types::Address, + ethers::types::{ + Address, + BlockNumber, + }, }; -pub type BlockNumber = u64; - /// EntropyReader is the read-only interface of the Entropy contract. #[async_trait] pub trait EntropyReader: Send + Sync { @@ -15,7 +16,7 @@ pub trait EntropyReader: Send + Sync { async fn get_request(&self, provider: Address, sequence_number: u64) -> Result>; - async fn get_block_number(&self) -> Result; + async fn get_block_number(&self, recent_block_status: BlockNumber) -> Result; } /// An in-flight request stored in the contract. @@ -26,7 +27,7 @@ pub struct Request { pub provider: Address, pub sequence_number: u64, // The block number where this request was created - pub block_number: BlockNumber, + pub block_number: u64, pub use_blockhash: bool, } @@ -35,7 +36,6 @@ pub struct Request { pub mod mock { use { crate::chain::reader::{ - BlockNumber, EntropyReader, Request, }, @@ -49,15 +49,15 @@ pub mod mock { /// This class is internally locked to allow tests to modify the in-flight requests while /// the API is also holding a pointer to the same data structure. pub struct MockEntropyReader { - block_number: RwLock, + block_number: RwLock, /// The set of requests that are currently in-flight. requests: RwLock>, } impl MockEntropyReader { pub fn with_requests( - block_number: BlockNumber, - requests: &[(Address, u64, BlockNumber, bool)], + block_number: u64, + requests: &[(Address, u64, u64, bool)], ) -> MockEntropyReader { MockEntropyReader { block_number: RwLock::new(block_number), @@ -80,7 +80,7 @@ pub mod mock { &self, provider: Address, sequence: u64, - block_number: BlockNumber, + block_number: u64, use_blockhash: bool, ) -> &Self { self.requests.write().unwrap().push(Request { @@ -92,7 +92,7 @@ pub mod mock { self } - pub fn set_block_number(&self, block_number: BlockNumber) -> &Self { + pub fn set_block_number(&self, block_number: u64) -> &Self { *(self.block_number.write().unwrap()) = block_number; self } @@ -114,7 +114,7 @@ pub mod mock { .map(|r| (*r).clone())) } - async fn get_block_number(&self) -> Result { + async fn get_block_number(&self) -> Result { Ok(*self.block_number.read().unwrap()) } } diff --git a/fortuna/src/command/run.rs b/fortuna/src/command/run.rs index c95f86b74..a6061e440 100644 --- a/fortuna/src/command/run.rs +++ b/fortuna/src/command/run.rs @@ -93,6 +93,7 @@ pub async fn run(opts: &RunOptions) -> Result<()> { contract, provider_address: opts.provider, reveal_delay_blocks: chain_config.reveal_delay_blocks, + recent_block_status: chain_config.block_status, }; chains.insert(chain_id.clone(), state); diff --git a/fortuna/src/config.rs b/fortuna/src/config.rs index cd0005a7a..c3bf30b7c 100644 --- a/fortuna/src/config.rs +++ b/fortuna/src/config.rs @@ -1,8 +1,5 @@ use { - crate::{ - api::ChainId, - chain::reader::BlockNumber, - }, + crate::api::ChainId, anyhow::{ anyhow, Result, @@ -15,7 +12,10 @@ use { Args, Parser, }, - ethers::types::Address, + ethers::types::{ + Address, + BlockNumber, + }, std::{ collections::HashMap, fs, @@ -132,9 +132,13 @@ pub struct EthereumConfig { pub contract_addr: Address, /// How many blocks to wait before revealing the random number. - pub reveal_delay_blocks: BlockNumber, + pub reveal_delay_blocks: u64, /// Use the legacy transaction format (for networks without EIP 1559) #[serde(default)] pub legacy_tx: bool, + + /// Use the legacy transaction format (for networks without EIP 1559) + #[serde(default)] + pub block_status: BlockNumber, }