Skip to content

Commit d02340d

Browse files
feat(fortuna): Support new Entropy v2 contract (#2691)
* upgrading to use the new contract API * deployable tester and contract testing * making this work on the new contracts * cleanup * cleanup another thing * check callback status in replica logic * use query() instead of query! macro --------- Co-authored-by: Tejas Badadare <tejasbadadare@gmail.com>
1 parent 33b3726 commit d02340d

22 files changed

+192
-232
lines changed

Cargo.lock

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/fortuna/.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
*secret*
44
*private-key*
55
.envrc
6-
fortuna.db
6+
fortuna.db*

apps/fortuna/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "fortuna"
3-
version = "7.7.0"
3+
version = "8.0.0"
44
edition = "2021"
55

66
[lib]
@@ -47,6 +47,7 @@ backoff = { version = "0.4.0", features = ["futures", "tokio"] }
4747
thiserror = "1.0.61"
4848
futures-locks = "0.7.1"
4949
sqlx = { version = "0.8", features = ["runtime-tokio", "sqlite", "chrono"] }
50+
num-traits = "0.2.19"
5051

5152
[dev-dependencies]
5253
axum-test = "13.1.1"

apps/fortuna/src/api/revelation.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ pub async fn revelation(
8989
.ok_or(RestError::NoPendingRequest)?;
9090
}
9191
None => {
92-
let maybe_request_fut = state.contract.get_request(state.provider_address, sequence);
92+
let maybe_request_fut = state
93+
.contract
94+
.get_request_v2(state.provider_address, sequence);
9395
let (maybe_request, current_block_number) =
9496
try_join!(maybe_request_fut, current_block_number_fut).map_err(|e| {
9597
tracing::error!(chain_id = chain_id, "RPC request failed {}", e);

apps/fortuna/src/chain/ethereum.rs

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -265,29 +265,22 @@ impl<T: JsonRpcClient + 'static> PythRandom<Provider<T>> {
265265

266266
#[async_trait]
267267
impl<T: JsonRpcClient + 'static> EntropyReader for PythRandom<Provider<T>> {
268-
async fn get_request(
268+
async fn get_request_v2(
269269
&self,
270270
provider_address: Address,
271271
sequence_number: u64,
272272
) -> Result<Option<reader::Request>> {
273-
let r = self
274-
.get_request(provider_address, sequence_number)
275-
// TODO: This doesn't work for lighlink right now. Figure out how to do this in lightlink
276-
// .block(ethers::core::types::BlockNumber::Finalized)
273+
let request = self
274+
.get_request_v2(provider_address, sequence_number)
277275
.call()
278276
.await?;
279-
280-
// sequence_number == 0 means the request does not exist.
281-
if r.sequence_number != 0 {
282-
Ok(Some(reader::Request {
283-
provider: r.provider,
284-
sequence_number: r.sequence_number,
285-
block_number: r.block_number,
286-
use_blockhash: r.use_blockhash,
287-
}))
288-
} else {
289-
Ok(None)
290-
}
277+
Ok(Some(reader::Request {
278+
provider: request.provider,
279+
sequence_number: request.sequence_number,
280+
block_number: request.block_number,
281+
use_blockhash: request.use_blockhash,
282+
callback_status: reader::RequestCallbackStatus::try_from(request.callback_status)?,
283+
}))
291284
}
292285

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

apps/fortuna/src/chain/reader.rs

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,11 @@ pub trait EntropyReader: Send + Sync {
6060
/// Get an in-flight request (if it exists)
6161
/// Note that if we support additional blockchains in the future, the type of `provider` may
6262
/// need to become more generic.
63-
async fn get_request(&self, provider: Address, sequence_number: u64)
64-
-> Result<Option<Request>>;
63+
async fn get_request_v2(
64+
&self,
65+
provider: Address,
66+
sequence_number: u64,
67+
) -> Result<Option<Request>>;
6568

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

@@ -93,12 +96,48 @@ pub struct Request {
9396
// The block number where this request was created
9497
pub block_number: BlockNumber,
9598
pub use_blockhash: bool,
99+
pub callback_status: RequestCallbackStatus,
100+
}
101+
102+
/// Status values for Request.callback_status
103+
#[derive(Clone, Debug, PartialEq, Eq)]
104+
pub enum RequestCallbackStatus {
105+
/// Not a request with callback
106+
CallbackNotNecessary = 0,
107+
/// A request with callback where the callback hasn't been invoked yet
108+
CallbackNotStarted = 1,
109+
/// A request with callback where the callback is currently in flight (this state is a reentry guard)
110+
CallbackInProgress = 2,
111+
/// A request with callback where the callback has been invoked and failed
112+
CallbackFailed = 3,
113+
}
114+
115+
impl TryFrom<u8> for RequestCallbackStatus {
116+
type Error = anyhow::Error;
117+
118+
fn try_from(value: u8) -> Result<Self> {
119+
match value {
120+
0 => Ok(RequestCallbackStatus::CallbackNotNecessary),
121+
1 => Ok(RequestCallbackStatus::CallbackNotStarted),
122+
2 => Ok(RequestCallbackStatus::CallbackInProgress),
123+
3 => Ok(RequestCallbackStatus::CallbackFailed),
124+
_ => Err(anyhow::anyhow!("Invalid callback status value: {}", value)),
125+
}
126+
}
127+
}
128+
129+
impl From<RequestCallbackStatus> for u8 {
130+
fn from(status: RequestCallbackStatus) -> Self {
131+
status as u8
132+
}
96133
}
97134

98135
#[cfg(test)]
99136
pub mod mock {
100137
use {
101-
crate::chain::reader::{BlockNumber, BlockStatus, EntropyReader, Request},
138+
crate::chain::reader::{
139+
BlockNumber, BlockStatus, EntropyReader, Request, RequestCallbackStatus,
140+
},
102141
anyhow::Result,
103142
axum::async_trait,
104143
ethers::types::{Address, U256},
@@ -129,6 +168,7 @@ pub mod mock {
129168
sequence_number: s,
130169
block_number: b,
131170
use_blockhash: u,
171+
callback_status: RequestCallbackStatus::CallbackNotNecessary,
132172
})
133173
.collect(),
134174
),
@@ -148,6 +188,7 @@ pub mod mock {
148188
sequence_number: sequence,
149189
block_number,
150190
use_blockhash,
191+
callback_status: RequestCallbackStatus::CallbackNotNecessary,
151192
});
152193
self
153194
}
@@ -160,7 +201,7 @@ pub mod mock {
160201

161202
#[async_trait]
162203
impl EntropyReader for MockEntropyReader {
163-
async fn get_request(
204+
async fn get_request_v2(
164205
&self,
165206
provider: Address,
166207
sequence_number: u64,

apps/fortuna/src/command/get_request.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@ pub async fn get_request(opts: &GetRequestOptions) -> Result<()> {
1414
&Config::load(&opts.config.config)?.get_chain_config(&opts.chain_id)?,
1515
)?);
1616

17-
let p = contract.get_provider_info(opts.provider).call().await?;
17+
let p = contract.get_provider_info_v2(opts.provider).call().await?;
1818

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

2121
let r = contract
22-
.get_request(opts.provider, opts.sequence)
22+
.get_request_v2(opts.provider, opts.sequence)
2323
.call()
2424
.await?;
2525
tracing::info!("Found request: {:?}", r);

apps/fortuna/src/command/inspect.rs

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use {
22
crate::{
3-
chain::ethereum::{EntropyStructsRequest, PythContract},
3+
chain::ethereum::{EntropyStructsV2Request, PythContract},
44
config::{Config, EthereumConfig, InspectOptions},
55
},
66
anyhow::Result,
@@ -42,7 +42,10 @@ async fn inspect_chain(
4242

4343
let contract = PythContract::from_config(chain_config)?;
4444
let entropy_provider = contract.get_default_provider().call().await?;
45-
let provider_info = contract.get_provider_info(entropy_provider).call().await?;
45+
let provider_info = contract
46+
.get_provider_info_v2(entropy_provider)
47+
.call()
48+
.await?;
4649
let mut current_request_number = provider_info.sequence_number;
4750
println!("Initial request number: {current_request_number}");
4851
let last_request_number = current_request_number.saturating_sub(num_requests);
@@ -60,12 +63,12 @@ async fn inspect_chain(
6063
break;
6164
}
6265
multicall.add_call(
63-
contract.get_request(entropy_provider, current_request_number),
66+
contract.get_request_v2(entropy_provider, current_request_number),
6467
false,
6568
);
6669
current_request_number -= 1;
6770
}
68-
let return_data: Vec<EntropyStructsRequest> = multicall.call_array().await?;
71+
let return_data: Vec<EntropyStructsV2Request> = multicall.call_array().await?;
6972
for request in return_data {
7073
process_request(rpc_provider.clone(), request).await?;
7174
}
@@ -75,7 +78,7 @@ async fn inspect_chain(
7578
println!("Multicall not deployed in this chain, fetching requests one by one");
7679
while current_request_number > last_request_number {
7780
let request = contract
78-
.get_request(entropy_provider, current_request_number)
81+
.get_request_v2(entropy_provider, current_request_number)
7982
.call()
8083
.await?;
8184
process_request(rpc_provider.clone(), request).await?;
@@ -90,9 +93,9 @@ async fn inspect_chain(
9093

9194
async fn process_request(
9295
rpc_provider: Provider<Http>,
93-
request: EntropyStructsRequest,
96+
request: EntropyStructsV2Request,
9497
) -> Result<()> {
95-
if request.sequence_number != 0 && request.is_request_with_callback {
98+
if request.sequence_number != 0 && request.callback_status != 0 {
9699
let block = rpc_provider
97100
.get_block(request.block_number)
98101
.await?

apps/fortuna/src/command/run.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ async fn setup_chain_state(
248248
});
249249

250250
let provider_info = contract
251-
.get_provider_info(*provider)
251+
.get_provider_info_v2(*provider)
252252
.call()
253253
.await
254254
.map_err(|e| anyhow!("Failed to get provider info: {}", e))?;

apps/fortuna/src/command/setup_provider.rs

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use {
22
crate::{
33
api::{get_register_uri, ChainId},
4-
chain::ethereum::{EntropyStructsProviderInfo, SignablePythContract},
4+
chain::ethereum::{EntropyStructsV2ProviderInfo, SignablePythContract},
55
command::register_provider::{register_provider_from_config, CommitmentMetadata},
66
config::{Config, EthereumConfig, SetupProviderOptions},
77
state::{HashChainState, PebbleHashChain},
@@ -76,7 +76,10 @@ async fn setup_chain_provider(
7676
let contract = Arc::new(SignablePythContract::from_config(chain_config, &private_key).await?);
7777

7878
tracing::info!("Fetching provider info");
79-
let provider_info = contract.get_provider_info(provider_address).call().await?;
79+
let provider_info = contract
80+
.get_provider_info_v2(provider_address)
81+
.call()
82+
.await?;
8083
tracing::info!("Provider info: {:?}", provider_info);
8184

8285
let mut register = false;
@@ -147,7 +150,10 @@ async fn setup_chain_provider(
147150
tracing::info!("Registered");
148151
}
149152

150-
let provider_info = contract.get_provider_info(provider_address).call().await?;
153+
let provider_info = contract
154+
.get_provider_info_v2(provider_address)
155+
.call()
156+
.await?;
151157

152158
if register || !chain_config.sync_fee_only_on_register {
153159
sync_fee(&contract, &provider_info, chain_config.fee)
@@ -176,12 +182,16 @@ async fn setup_chain_provider(
176182
.in_current_span()
177183
.await?;
178184

185+
sync_default_gas_limit(&contract, &provider_info, chain_config.gas_limit)
186+
.in_current_span()
187+
.await?;
188+
179189
Ok(())
180190
}
181191

182192
async fn sync_uri(
183193
contract: &Arc<SignablePythContract>,
184-
provider_info: &EntropyStructsProviderInfo,
194+
provider_info: &EntropyStructsV2ProviderInfo,
185195
uri: String,
186196
) -> Result<()> {
187197
let uri_as_bytes: Bytes = AbiBytes::from(uri.as_str()).into();
@@ -201,7 +211,7 @@ async fn sync_uri(
201211

202212
async fn sync_fee(
203213
contract: &Arc<SignablePythContract>,
204-
provider_info: &EntropyStructsProviderInfo,
214+
provider_info: &EntropyStructsV2ProviderInfo,
205215
provider_fee: u128,
206216
) -> Result<()> {
207217
if provider_info.fee_in_wei != provider_fee {
@@ -220,7 +230,7 @@ async fn sync_fee(
220230

221231
async fn sync_fee_manager(
222232
contract: &Arc<SignablePythContract>,
223-
provider_info: &EntropyStructsProviderInfo,
233+
provider_info: &EntropyStructsV2ProviderInfo,
224234
fee_manager: Address,
225235
) -> Result<()> {
226236
if provider_info.fee_manager != fee_manager {
@@ -234,7 +244,7 @@ async fn sync_fee_manager(
234244

235245
async fn sync_max_num_hashes(
236246
contract: &Arc<SignablePythContract>,
237-
provider_info: &EntropyStructsProviderInfo,
247+
provider_info: &EntropyStructsV2ProviderInfo,
238248
max_num_hashes: u32,
239249
) -> Result<()> {
240250
if provider_info.max_num_hashes != max_num_hashes {
@@ -250,3 +260,25 @@ async fn sync_max_num_hashes(
250260
}
251261
Ok(())
252262
}
263+
264+
async fn sync_default_gas_limit(
265+
contract: &Arc<SignablePythContract>,
266+
provider_info: &EntropyStructsV2ProviderInfo,
267+
default_gas_limit: u32,
268+
) -> Result<()> {
269+
if provider_info.default_gas_limit != default_gas_limit {
270+
tracing::info!(
271+
"Updating provider default gas limit to {:?}",
272+
default_gas_limit
273+
);
274+
if let Some(receipt) = contract
275+
.set_default_gas_limit(default_gas_limit)
276+
.send()
277+
.await?
278+
.await?
279+
{
280+
tracing::info!("Updated provider default gas limit to : {:?}", receipt);
281+
}
282+
}
283+
Ok(())
284+
}

0 commit comments

Comments
 (0)