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
32 changes: 32 additions & 0 deletions apps/fortuna/src/chain/ethereum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,38 @@ impl<T: JsonRpcClient + 'static + Clone> SignablePythContractInner<T> {
}
}

/// Submit a request for a random number to the contract.
///
/// This method is a version of the autogenned `request` method that parses the emitted logs
/// to return the sequence number of the created Request.
pub async fn request_with_callback_wrapper(
&self,
provider: &Address,
user_randomness: &[u8; 32],
) -> Result<u64> {
let fee = self.get_fee(*provider).call().await?;

if let Some(r) = self
.request_with_callback(*provider, *user_randomness)
.value(fee)
.send()
.await?
.await?
{
// Extract Log from TransactionReceipt.
let l: RawLog = r.logs[0].clone().into();
if let PythRandomEvents::RequestedWithCallbackFilter(r) =
PythRandomEvents::decode_log(&l)?
{
Ok(r.request.sequence_number)
} else {
Err(anyhow!("No log with sequence number"))
}
} else {
Err(anyhow!("Request failed"))
}
}

/// Reveal the generated random number to the contract.
///
/// This method is a version of the autogenned `reveal` method that parses the emitted logs
Expand Down
75 changes: 44 additions & 31 deletions apps/fortuna/src/command/generate.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use {
crate::{
api::GetRandomValueResponse,
chain::ethereum::SignablePythContract,
chain::ethereum::{RevealedWithCallbackFilter, SignablePythContract},
config::{Config, GenerateOptions},
},
anyhow::Result,
base64::{engine::general_purpose::STANDARD as base64_standard_engine, Engine as _},
ethers::providers::Middleware,
std::sync::Arc,
tokio::time::{self, Duration},
};

/// Run the entire random number generation protocol to produce a random number.
Expand All @@ -22,42 +23,54 @@ pub async fn generate(opts: &GenerateOptions) -> Result<()> {
let user_randomness = rand::random::<[u8; 32]>();
let provider = opts.provider;

let mut last_block_number = contract.provider().get_block_number().await?;
tracing::info!(block_number = last_block_number.as_u64(), "block number");

tracing::info!("Requesting random number...");

// Request a random number on the contract
let sequence_number = contract
.request_wrapper(&provider, &user_randomness, opts.blockhash)
.request_with_callback_wrapper(&provider, &user_randomness)
.await?;

tracing::info!(sequence_number = sequence_number, "random number requested",);
tracing::info!(sequence_number = sequence_number, "Random number requested",);

// Get the committed value from the provider
let resp = reqwest::get(opts.url.join(&format!(
"/v1/chains/{}/revelations/{}",
opts.chain_id, sequence_number
))?)
.await?
.json::<GetRandomValueResponse>()
.await?;
let mut num_retries = 0;
let mut found_request = false;
while !found_request && num_retries < 10 {
let current_block_number = contract.provider().get_block_number().await?;
tracing::info!(
start_block = last_block_number.as_u64(),
end_block = current_block_number.as_u64(),
"Checking events between blocks."
);

tracing::info!(
response = base64_standard_engine.encode(resp.value.data()),
"Retrieved the provider's random value.",
);
let provider_randomness = resp.value.data();

// Submit the provider's and our values to the contract to reveal the random number.
let random_value = contract
.reveal_wrapper(
&provider,
sequence_number,
&user_randomness,
provider_randomness,
)
.await?;
let mut event = contract.revealed_with_callback_filter();
event.filter = event
.filter
.from_block(last_block_number)
.to_block(current_block_number);

tracing::info!(
number = base64_standard_engine.encode(random_value),
"Random number generated."
);
let res: Vec<RevealedWithCallbackFilter> = event.query().await?;

for r in res.iter() {
if r.request.sequence_number == sequence_number && r.request.provider == provider {
tracing::info!(
number = base64_standard_engine.encode(r.random_number),
"Random number generated."
);
found_request = true;
}
}

last_block_number = current_block_number;
num_retries += 1;
time::sleep(Duration::from_secs(1)).await;
}

if !found_request {
tracing::info!("Failed to receive a callback with the random number.");
}

Ok(())
}
9 changes: 6 additions & 3 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::{PythContract, Request},
chain::ethereum::{EntropyStructsV2Request, PythContract},
config::{Config, EthereumConfig, InspectOptions},
},
anyhow::Result,
Expand Down Expand Up @@ -66,7 +66,7 @@ async fn inspect_chain(
);
current_request_number -= 1;
}
let return_data: Vec<Request> = 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 @@ -89,7 +89,10 @@ async fn inspect_chain(
Ok(())
}

async fn process_request(rpc_provider: Provider<Http>, request: Request) -> Result<()> {
async fn process_request(
rpc_provider: Provider<Http>,
request: EntropyStructsV2Request,
) -> Result<()> {
if request.sequence_number != 0 && request.callback_status != 0 {
let block = rpc_provider
.get_block(request.block_number)
Expand Down
10 changes: 5 additions & 5 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::{ProviderInfo, SignablePythContract},
chain::ethereum::{EntropyStructsV2ProviderInfo, SignablePythContract},
command::register_provider::{register_provider_from_config, CommitmentMetadata},
config::{Config, EthereumConfig, SetupProviderOptions},
state::{HashChainState, PebbleHashChain},
Expand Down Expand Up @@ -178,7 +178,7 @@ async fn setup_chain_provider(

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

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

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

async fn sync_max_num_hashes(
contract: &Arc<SignablePythContract>,
provider_info: &ProviderInfo,
provider_info: &EntropyStructsV2ProviderInfo,
max_num_hashes: u32,
) -> Result<()> {
if provider_info.max_num_hashes != max_num_hashes {
Expand Down
1 change: 0 additions & 1 deletion apps/fortuna/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ mod setup_provider;
mod withdraw_fees;

const DEFAULT_RPC_ADDR: &str = "127.0.0.1:34000";
const DEFAULT_HTTP_ADDR: &str = "http://127.0.0.1:34000";

#[derive(Parser, Debug)]
#[command(name = crate_name!())]
Expand Down
8 changes: 0 additions & 8 deletions apps/fortuna/src/config/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use {
crate::{api::ChainId, config::ConfigOptions},
clap::Args,
ethers::types::Address,
reqwest::Url,
};

#[derive(Args, Clone, Debug)]
Expand All @@ -27,11 +26,4 @@ pub struct GenerateOptions {
/// Submit a randomness request to this provider
#[arg(long = "provider")]
pub provider: Address,

#[arg(long = "url")]
#[arg(default_value = super::DEFAULT_HTTP_ADDR)]
pub url: Url,

#[arg(short = 'b')]
pub blockhash: bool,
}
Loading
Loading