Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion apps/fortuna/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
*secret*
*private-key*
.envrc
fortuna.db
fortuna.db*
3 changes: 2 additions & 1 deletion apps/fortuna/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "fortuna"
version = "7.7.0"
version = "8.0.0"
edition = "2021"

[lib]
Expand Down Expand Up @@ -47,6 +47,7 @@ backoff = { version = "0.4.0", features = ["futures", "tokio"] }
thiserror = "1.0.61"
futures-locks = "0.7.1"
sqlx = { version = "0.8", features = ["runtime-tokio", "sqlite", "chrono"] }
num-traits = "0.2.19"

[dev-dependencies]
axum-test = "13.1.1"
4 changes: 3 additions & 1 deletion apps/fortuna/src/api/revelation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ pub async fn revelation(
.ok_or(RestError::NoPendingRequest)?;
}
None => {
let maybe_request_fut = state.contract.get_request(state.provider_address, sequence);
let maybe_request_fut = state
.contract
.get_request_v2(state.provider_address, sequence);
let (maybe_request, current_block_number) =
try_join!(maybe_request_fut, current_block_number_fut).map_err(|e| {
tracing::error!(chain_id = chain_id, "RPC request failed {}", e);
Expand Down
27 changes: 10 additions & 17 deletions apps/fortuna/src/chain/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,29 +265,22 @@ impl<T: JsonRpcClient + 'static> PythRandom<Provider<T>> {

#[async_trait]
impl<T: JsonRpcClient + 'static> EntropyReader for PythRandom<Provider<T>> {
async fn get_request(
async fn get_request_v2(
&self,
provider_address: Address,
sequence_number: u64,
) -> Result<Option<reader::Request>> {
let r = self
.get_request(provider_address, sequence_number)
// TODO: This doesn't work for lighlink right now. Figure out how to do this in lightlink
// .block(ethers::core::types::BlockNumber::Finalized)
let request = self
.get_request_v2(provider_address, sequence_number)
.call()
.await?;

// sequence_number == 0 means the request does not exist.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this removed? I know that this check exists in some other places, but if we want to be safe and avoid unintended changes, we can keep it as is?

if r.sequence_number != 0 {
Ok(Some(reader::Request {
provider: r.provider,
sequence_number: r.sequence_number,
block_number: r.block_number,
use_blockhash: r.use_blockhash,
}))
} else {
Ok(None)
}
Ok(Some(reader::Request {
provider: request.provider,
sequence_number: request.sequence_number,
block_number: request.block_number,
use_blockhash: request.use_blockhash,
callback_status: reader::RequestCallbackStatus::try_from(request.callback_status)?,
}))
}

async fn get_block_number(&self, confirmed_block_status: BlockStatus) -> Result<BlockNumber> {
Expand Down
49 changes: 45 additions & 4 deletions apps/fortuna/src/chain/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,11 @@ pub trait EntropyReader: Send + Sync {
/// Get an in-flight request (if it exists)
/// Note that if we support additional blockchains in the future, the type of `provider` may
/// need to become more generic.
async fn get_request(&self, provider: Address, sequence_number: u64)
-> Result<Option<Request>>;
async fn get_request_v2(
&self,
provider: Address,
sequence_number: u64,
) -> Result<Option<Request>>;

async fn get_block_number(&self, confirmed_block_status: BlockStatus) -> Result<BlockNumber>;

Expand Down Expand Up @@ -93,12 +96,48 @@ pub struct Request {
// The block number where this request was created
pub block_number: BlockNumber,
pub use_blockhash: bool,
pub callback_status: RequestCallbackStatus,
}

/// Status values for Request.callback_status
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum RequestCallbackStatus {
/// Not a request with callback
CallbackNotNecessary = 0,
/// A request with callback where the callback hasn't been invoked yet
CallbackNotStarted = 1,
/// A request with callback where the callback is currently in flight (this state is a reentry guard)
CallbackInProgress = 2,
/// A request with callback where the callback has been invoked and failed
CallbackFailed = 3,
}

impl TryFrom<u8> for RequestCallbackStatus {
type Error = anyhow::Error;

fn try_from(value: u8) -> Result<Self> {
match value {
0 => Ok(RequestCallbackStatus::CallbackNotNecessary),
1 => Ok(RequestCallbackStatus::CallbackNotStarted),
2 => Ok(RequestCallbackStatus::CallbackInProgress),
3 => Ok(RequestCallbackStatus::CallbackFailed),
_ => Err(anyhow::anyhow!("Invalid callback status value: {}", value)),
}
}
}

impl From<RequestCallbackStatus> for u8 {
fn from(status: RequestCallbackStatus) -> Self {
status as u8
}
}

#[cfg(test)]
pub mod mock {
use {
crate::chain::reader::{BlockNumber, BlockStatus, EntropyReader, Request},
crate::chain::reader::{
BlockNumber, BlockStatus, EntropyReader, Request, RequestCallbackStatus,
},
anyhow::Result,
axum::async_trait,
ethers::types::{Address, U256},
Expand Down Expand Up @@ -129,6 +168,7 @@ pub mod mock {
sequence_number: s,
block_number: b,
use_blockhash: u,
callback_status: RequestCallbackStatus::CallbackNotNecessary,
})
.collect(),
),
Expand All @@ -148,6 +188,7 @@ pub mod mock {
sequence_number: sequence,
block_number,
use_blockhash,
callback_status: RequestCallbackStatus::CallbackNotNecessary,
});
self
}
Expand All @@ -160,7 +201,7 @@ pub mod mock {

#[async_trait]
impl EntropyReader for MockEntropyReader {
async fn get_request(
async fn get_request_v2(
&self,
provider: Address,
sequence_number: u64,
Expand Down
4 changes: 2 additions & 2 deletions apps/fortuna/src/command/get_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,12 @@ pub async fn get_request(opts: &GetRequestOptions) -> Result<()> {
&Config::load(&opts.config.config)?.get_chain_config(&opts.chain_id)?,
)?);

let p = contract.get_provider_info(opts.provider).call().await?;
let p = contract.get_provider_info_v2(opts.provider).call().await?;

tracing::info!("Found provider: {:?}", p);

let r = contract
.get_request(opts.provider, opts.sequence)
.get_request_v2(opts.provider, opts.sequence)
.call()
.await?;
tracing::info!("Found request: {:?}", r);
Expand Down
17 changes: 10 additions & 7 deletions apps/fortuna/src/command/inspect.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {
crate::{
chain::ethereum::{EntropyStructsRequest, PythContract},
chain::ethereum::{EntropyStructsV2Request, PythContract},
config::{Config, EthereumConfig, InspectOptions},
},
anyhow::Result,
Expand Down Expand Up @@ -42,7 +42,10 @@ async fn inspect_chain(

let contract = PythContract::from_config(chain_config)?;
let entropy_provider = contract.get_default_provider().call().await?;
let provider_info = contract.get_provider_info(entropy_provider).call().await?;
let provider_info = contract
.get_provider_info_v2(entropy_provider)
.call()
.await?;
let mut current_request_number = provider_info.sequence_number;
println!("Initial request number: {current_request_number}");
let last_request_number = current_request_number.saturating_sub(num_requests);
Expand All @@ -60,12 +63,12 @@ async fn inspect_chain(
break;
}
multicall.add_call(
contract.get_request(entropy_provider, current_request_number),
contract.get_request_v2(entropy_provider, current_request_number),
false,
);
current_request_number -= 1;
}
let return_data: Vec<EntropyStructsRequest> = multicall.call_array().await?;
let return_data: Vec<EntropyStructsV2Request> = multicall.call_array().await?;
for request in return_data {
process_request(rpc_provider.clone(), request).await?;
}
Expand All @@ -75,7 +78,7 @@ async fn inspect_chain(
println!("Multicall not deployed in this chain, fetching requests one by one");
while current_request_number > last_request_number {
let request = contract
.get_request(entropy_provider, current_request_number)
.get_request_v2(entropy_provider, current_request_number)
.call()
.await?;
process_request(rpc_provider.clone(), request).await?;
Expand All @@ -90,9 +93,9 @@ async fn inspect_chain(

async fn process_request(
rpc_provider: Provider<Http>,
request: EntropyStructsRequest,
request: EntropyStructsV2Request,
) -> Result<()> {
if request.sequence_number != 0 && request.is_request_with_callback {
if request.sequence_number != 0 && request.callback_status != 0 {
let block = rpc_provider
.get_block(request.block_number)
.await?
Expand Down
2 changes: 1 addition & 1 deletion apps/fortuna/src/command/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ async fn setup_chain_state(
});

let provider_info = contract
.get_provider_info(*provider)
.get_provider_info_v2(*provider)
.call()
.await
.map_err(|e| anyhow!("Failed to get provider info: {}", e))?;
Expand Down
46 changes: 39 additions & 7 deletions apps/fortuna/src/command/setup_provider.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use {
crate::{
api::{get_register_uri, ChainId},
chain::ethereum::{EntropyStructsProviderInfo, SignablePythContract},
chain::ethereum::{EntropyStructsV2ProviderInfo, SignablePythContract},
command::register_provider::{register_provider_from_config, CommitmentMetadata},
config::{Config, EthereumConfig, SetupProviderOptions},
state::{HashChainState, PebbleHashChain},
Expand Down Expand Up @@ -76,7 +76,10 @@ async fn setup_chain_provider(
let contract = Arc::new(SignablePythContract::from_config(chain_config, &private_key).await?);

tracing::info!("Fetching provider info");
let provider_info = contract.get_provider_info(provider_address).call().await?;
let provider_info = contract
.get_provider_info_v2(provider_address)
.call()
.await?;
tracing::info!("Provider info: {:?}", provider_info);

let mut register = false;
Expand Down Expand Up @@ -147,7 +150,10 @@ async fn setup_chain_provider(
tracing::info!("Registered");
}

let provider_info = contract.get_provider_info(provider_address).call().await?;
let provider_info = contract
.get_provider_info_v2(provider_address)
.call()
.await?;

if register || !chain_config.sync_fee_only_on_register {
sync_fee(&contract, &provider_info, chain_config.fee)
Expand Down Expand Up @@ -176,12 +182,16 @@ async fn setup_chain_provider(
.in_current_span()
.await?;

sync_default_gas_limit(&contract, &provider_info, chain_config.gas_limit)
.in_current_span()
.await?;

Ok(())
}

async fn sync_uri(
contract: &Arc<SignablePythContract>,
provider_info: &EntropyStructsProviderInfo,
provider_info: &EntropyStructsV2ProviderInfo,
uri: String,
) -> Result<()> {
let uri_as_bytes: Bytes = AbiBytes::from(uri.as_str()).into();
Expand All @@ -201,7 +211,7 @@ async fn sync_uri(

async fn sync_fee(
contract: &Arc<SignablePythContract>,
provider_info: &EntropyStructsProviderInfo,
provider_info: &EntropyStructsV2ProviderInfo,
provider_fee: u128,
) -> Result<()> {
if provider_info.fee_in_wei != provider_fee {
Expand All @@ -220,7 +230,7 @@ async fn sync_fee(

async fn sync_fee_manager(
contract: &Arc<SignablePythContract>,
provider_info: &EntropyStructsProviderInfo,
provider_info: &EntropyStructsV2ProviderInfo,
fee_manager: Address,
) -> Result<()> {
if provider_info.fee_manager != fee_manager {
Expand All @@ -234,7 +244,7 @@ async fn sync_fee_manager(

async fn sync_max_num_hashes(
contract: &Arc<SignablePythContract>,
provider_info: &EntropyStructsProviderInfo,
provider_info: &EntropyStructsV2ProviderInfo,
max_num_hashes: u32,
) -> Result<()> {
if provider_info.max_num_hashes != max_num_hashes {
Expand All @@ -250,3 +260,25 @@ async fn sync_max_num_hashes(
}
Ok(())
}

async fn sync_default_gas_limit(
contract: &Arc<SignablePythContract>,
provider_info: &EntropyStructsV2ProviderInfo,
default_gas_limit: u32,
) -> Result<()> {
if provider_info.default_gas_limit != default_gas_limit {
tracing::info!(
"Updating provider default gas limit to {:?}",
default_gas_limit
);
if let Some(receipt) = contract
.set_default_gas_limit(default_gas_limit)
.send()
.await?
.await?
{
tracing::info!("Updated provider default gas limit to : {:?}", receipt);
}
}
Ok(())
}
5 changes: 4 additions & 1 deletion apps/fortuna/src/command/withdraw_fees.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ pub async fn withdraw_fees_for_chain(
retained_balance: u128,
) -> Result<()> {
tracing::info!("Fetching fees for provider: {:?}", provider_address);
let provider_info = contract.get_provider_info(provider_address).call().await?;
let provider_info = contract
.get_provider_info_v2(provider_address)
.call()
.await?;
let fees = provider_info.accrued_fees_in_wei;
tracing::info!("Accrued fees: {} wei", fees);

Expand Down
Loading