feat(Fortuna): add finality checks (#1322)
This commit is contained in:
parent
281ef68753
commit
eaaa74a44e
|
@ -1486,7 +1486,7 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "fortuna"
|
||||
version = "3.2.4"
|
||||
version = "3.3.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"axum",
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[package]
|
||||
name = "fortuna"
|
||||
version = "3.2.4"
|
||||
version = "3.3.4"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
|
|
|
@ -2,6 +2,7 @@ use {
|
|||
crate::{
|
||||
chain::reader::{
|
||||
BlockNumber,
|
||||
BlockStatus,
|
||||
EntropyReader,
|
||||
},
|
||||
state::HashChainState,
|
||||
|
@ -73,14 +74,17 @@ impl ApiState {
|
|||
#[derive(Clone)]
|
||||
pub struct BlockchainState {
|
||||
/// The hash chain(s) required to serve random numbers for this blockchain
|
||||
pub state: Arc<HashChainState>,
|
||||
pub state: Arc<HashChainState>,
|
||||
/// The contract that the server is fulfilling requests for.
|
||||
pub contract: Arc<dyn EntropyReader>,
|
||||
pub contract: Arc<dyn EntropyReader>,
|
||||
/// The address of the provider that this server is operating for.
|
||||
pub provider_address: Address,
|
||||
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: BlockNumber,
|
||||
/// The BlockStatus of the block that is considered to be confirmed on the blockchain.
|
||||
/// For eg., Finalized, Safe
|
||||
pub confirmed_block_status: BlockStatus,
|
||||
}
|
||||
|
||||
pub struct Metrics {
|
||||
|
@ -203,7 +207,10 @@ mod test {
|
|||
BlockchainState,
|
||||
GetRandomValueResponse,
|
||||
},
|
||||
chain::reader::mock::MockEntropyReader,
|
||||
chain::reader::{
|
||||
mock::MockEntropyReader,
|
||||
BlockStatus,
|
||||
},
|
||||
state::{
|
||||
HashChainState,
|
||||
PebbleHashChain,
|
||||
|
@ -238,19 +245,21 @@ mod test {
|
|||
let eth_read = Arc::new(MockEntropyReader::with_requests(10, &[]));
|
||||
|
||||
let eth_state = BlockchainState {
|
||||
state: ETH_CHAIN.clone(),
|
||||
contract: eth_read.clone(),
|
||||
provider_address: PROVIDER,
|
||||
reveal_delay_blocks: 1,
|
||||
state: ETH_CHAIN.clone(),
|
||||
contract: eth_read.clone(),
|
||||
provider_address: PROVIDER,
|
||||
reveal_delay_blocks: 1,
|
||||
confirmed_block_status: BlockStatus::Latest,
|
||||
};
|
||||
|
||||
let avax_read = Arc::new(MockEntropyReader::with_requests(10, &[]));
|
||||
|
||||
let avax_state = BlockchainState {
|
||||
state: AVAX_CHAIN.clone(),
|
||||
contract: avax_read.clone(),
|
||||
provider_address: PROVIDER,
|
||||
reveal_delay_blocks: 2,
|
||||
state: AVAX_CHAIN.clone(),
|
||||
contract: avax_read.clone(),
|
||||
provider_address: PROVIDER,
|
||||
reveal_delay_blocks: 2,
|
||||
confirmed_block_status: BlockStatus::Latest,
|
||||
};
|
||||
|
||||
let api_state = ApiState::new(&[
|
||||
|
|
|
@ -62,7 +62,9 @@ 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.confirmed_block_status);
|
||||
|
||||
let (maybe_request, current_block_number) =
|
||||
try_join!(maybe_request_fut, current_block_number_fut).map_err(|e| {
|
||||
|
|
|
@ -1,16 +1,16 @@
|
|||
use {
|
||||
crate::{
|
||||
chain::{
|
||||
reader,
|
||||
reader::{
|
||||
BlockNumber,
|
||||
EntropyReader,
|
||||
},
|
||||
chain::reader::{
|
||||
self,
|
||||
BlockNumber,
|
||||
BlockStatus,
|
||||
EntropyReader,
|
||||
},
|
||||
config::EthereumConfig,
|
||||
},
|
||||
anyhow::{
|
||||
anyhow,
|
||||
Error,
|
||||
Result,
|
||||
},
|
||||
axum::async_trait,
|
||||
|
@ -39,7 +39,10 @@ use {
|
|||
LocalWallet,
|
||||
Signer,
|
||||
},
|
||||
types::transaction::eip2718::TypedTransaction,
|
||||
types::{
|
||||
transaction::eip2718::TypedTransaction,
|
||||
BlockNumber as EthersBlockNumber,
|
||||
},
|
||||
},
|
||||
sha3::{
|
||||
Digest,
|
||||
|
@ -209,7 +212,17 @@ impl EntropyReader for PythContract {
|
|||
}
|
||||
}
|
||||
|
||||
async fn get_block_number(&self) -> Result<BlockNumber> {
|
||||
Ok(self.client().get_block_number().await?.as_u64())
|
||||
async fn get_block_number(&self, confirmed_block_status: BlockStatus) -> Result<BlockNumber> {
|
||||
let block_number: EthersBlockNumber = confirmed_block_status.into();
|
||||
let block = self
|
||||
.client()
|
||||
.get_block(block_number)
|
||||
.await?
|
||||
.ok_or_else(|| Error::msg("pending block confirmation"))?;
|
||||
|
||||
Ok(block
|
||||
.number
|
||||
.ok_or_else(|| Error::msg("pending confirmation"))?
|
||||
.as_u64())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,37 @@
|
|||
use {
|
||||
anyhow::Result,
|
||||
axum::async_trait,
|
||||
ethers::types::Address,
|
||||
ethers::types::{
|
||||
Address,
|
||||
BlockNumber as EthersBlockNumber,
|
||||
},
|
||||
};
|
||||
|
||||
pub type BlockNumber = u64;
|
||||
|
||||
#[derive(
|
||||
Copy, Clone, Debug, Default, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize,
|
||||
)]
|
||||
pub enum BlockStatus {
|
||||
/// Latest block
|
||||
#[default]
|
||||
Latest,
|
||||
/// Finalized block accepted as canonical
|
||||
Finalized,
|
||||
/// Safe head block
|
||||
Safe,
|
||||
}
|
||||
|
||||
impl Into<EthersBlockNumber> for BlockStatus {
|
||||
fn into(self) -> EthersBlockNumber {
|
||||
match self {
|
||||
BlockStatus::Latest => EthersBlockNumber::Latest,
|
||||
BlockStatus::Finalized => EthersBlockNumber::Finalized,
|
||||
BlockStatus::Safe => EthersBlockNumber::Safe,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// EntropyReader is the read-only interface of the Entropy contract.
|
||||
#[async_trait]
|
||||
pub trait EntropyReader: Send + Sync {
|
||||
|
@ -15,7 +41,7 @@ pub trait EntropyReader: Send + Sync {
|
|||
async fn get_request(&self, provider: Address, sequence_number: u64)
|
||||
-> Result<Option<Request>>;
|
||||
|
||||
async fn get_block_number(&self) -> Result<BlockNumber>;
|
||||
async fn get_block_number(&self, confirmed_block_status: BlockStatus) -> Result<BlockNumber>;
|
||||
}
|
||||
|
||||
/// An in-flight request stored in the contract.
|
||||
|
@ -36,6 +62,7 @@ pub mod mock {
|
|||
use {
|
||||
crate::chain::reader::{
|
||||
BlockNumber,
|
||||
BlockStatus,
|
||||
EntropyReader,
|
||||
Request,
|
||||
},
|
||||
|
@ -114,7 +141,10 @@ pub mod mock {
|
|||
.map(|r| (*r).clone()))
|
||||
}
|
||||
|
||||
async fn get_block_number(&self) -> Result<BlockNumber> {
|
||||
async fn get_block_number(
|
||||
&self,
|
||||
confirmed_block_status: BlockStatus,
|
||||
) -> Result<BlockNumber> {
|
||||
Ok(*self.block_number.read().unwrap())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,6 +93,7 @@ pub async fn run(opts: &RunOptions) -> Result<()> {
|
|||
contract,
|
||||
provider_address: opts.provider,
|
||||
reveal_delay_blocks: chain_config.reveal_delay_blocks,
|
||||
confirmed_block_status: chain_config.confirmed_block_status,
|
||||
};
|
||||
|
||||
chains.insert(chain_id.clone(), state);
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
use {
|
||||
crate::{
|
||||
api::ChainId,
|
||||
chain::reader::BlockNumber,
|
||||
chain::reader::{
|
||||
BlockNumber,
|
||||
BlockStatus,
|
||||
},
|
||||
},
|
||||
anyhow::{
|
||||
anyhow,
|
||||
|
@ -131,10 +134,18 @@ pub struct EthereumConfig {
|
|||
/// Address of a Pyth Randomness contract to interact with.
|
||||
pub contract_addr: Address,
|
||||
|
||||
/// How many blocks to wait before revealing the random number.
|
||||
/// reveal_delay_blocks - The difference between the block number with the
|
||||
/// confirmed_block_status(see below) and the block number of a request to
|
||||
/// Entropy should be greater than `reveal_delay_blocks` for Fortuna to reveal
|
||||
/// its commitment.
|
||||
pub reveal_delay_blocks: BlockNumber,
|
||||
|
||||
/// Use the legacy transaction format (for networks without EIP 1559)
|
||||
#[serde(default)]
|
||||
pub legacy_tx: bool,
|
||||
|
||||
/// The BlockStatus of the block that is considered confirmed.
|
||||
/// For example, Finalized, Safe, Latest
|
||||
#[serde(default)]
|
||||
pub confirmed_block_status: BlockStatus,
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue