Skip to content

Commit

Permalink
stuff
Browse files Browse the repository at this point in the history
  • Loading branch information
jayantk committed Oct 18, 2023
1 parent 76a3379 commit 9604aa4
Show file tree
Hide file tree
Showing 19 changed files with 347 additions and 122 deletions.
20 changes: 20 additions & 0 deletions pyth-rng/Cargo.lock

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

1 change: 1 addition & 0 deletions pyth-rng/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ reqwest = { version = "0.11.22", features = ["json", "blocking"] }
serde = { version = "1.0.188", features = ["derive"] }
serde_qs = { version = "0.12.0", features = ["axum"] }
serde_json = "1.0.107"
serde_yaml = "0.9.25"
sha3 = "0.10.8"
tokio = { version = "1.33.0", features = ["full"] }
tower-http = { version = "0.4.0", features = ["cors"] }
Expand Down
21 changes: 18 additions & 3 deletions pyth-rng/src/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,30 @@ use {
},
},
ethers::core::types::Address,
std::sync::Arc,
std::{
collections::HashMap,
sync::Arc,
},
};
pub use {
chain_ids::*,
index::*,
revelation::*,
};

mod chain_ids;
mod index;
mod revelation;

/// The state of the randomness service for a single blockchain.
pub type ChainId = String;

#[derive(Clone)]
pub struct ApiState {
pub chains: Arc<HashMap<ChainId, BlockchainState>>,
}

/// The state of the randomness service for a single blockchain.
pub struct BlockchainState {
/// The hash chain(s) required to serve random numbers for this blockchain
pub state: Arc<HashChainState>,
/// The EVM contract where the protocol is running.
Expand All @@ -32,10 +43,11 @@ pub struct ApiState {
pub provider_address: Address,
}


pub enum RestError {
/// The caller passed a sequence number that isn't within the supported range
InvalidSequenceNumber,
/// The caller passed an unsupported chain id
InvalidChainId,
/// The caller requested a random value that can't currently be revealed (because it
/// hasn't been committed to on-chain)
NoPendingRequest,
Expand All @@ -54,6 +66,9 @@ impl IntoResponse for RestError {
"The sequence number is out of the permitted range",
)
.into_response(),
RestError::InvalidChainId => {
(StatusCode::BAD_REQUEST, "The chain id is not supported").into_response()
}
RestError::NoPendingRequest => (
StatusCode::FORBIDDEN,
"The random value cannot currently be retrieved",
Expand Down
2 changes: 1 addition & 1 deletion pyth-rng/src/api/index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,5 @@ use axum::{
///
/// TODO: Dynamically generate this list if possible.
pub async fn index() -> impl IntoResponse {
Json(["/v1/revelation"])
Json(["/v1/chains", "/v1/chains/:chain_id/revelations/:sequence"])
}
36 changes: 24 additions & 12 deletions pyth-rng/src/api/revelation.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,53 @@
use {
crate::api::RestError,
crate::api::{
ChainId,
RestError,
},
anyhow::Result,
axum::{
extract::State,
extract::{
Path,
State,
},
Json,
},
pythnet_sdk::wire::array,
serde_qs::axum::QsQuery,
utoipa::{
IntoParams,
ToSchema,
},
};

// TODO: this should probably take path parameters /v1/revelation/<chain_id>/<sequence_number>
/// Reveal the random value for a given sequence number.
/// Reveal the random value for a given sequence number and blockchain.
///
/// Given a sequence number, retrieve the corresponding random value that this provider has committed to.
/// This endpoint will not return the random value unless someone has requested the sequence number on-chain.
///
/// Every blockchain supported by this service has a distinct sequence of random numbers and chain_id.
/// Callers must pass the appropriate chain_id to ensure they fetch the correct random number.
#[utoipa::path(
get,
path = "/v1/revelation",
path = "/v1/chains/{chain_id}/revelations/{sequence}",
responses(
(status = 200, description = "Random value successfully retrieved", body = GetRandomValueResponse),
(status = 403, description = "Random value cannot currently be retrieved", body = String)
),
params(
GetRandomValueQueryParams
)
params(GetRandomValueQueryParams)
)]
pub async fn revelation(
State(state): State<crate::api::ApiState>,
QsQuery(params): QsQuery<GetRandomValueQueryParams>,
Path(GetRandomValueQueryParams { chain_id, sequence }): Path<GetRandomValueQueryParams>,
) -> Result<Json<GetRandomValueResponse>, RestError> {
let sequence: u64 = params
.sequence
let sequence: u64 = sequence
.try_into()
.map_err(|_| RestError::InvalidSequenceNumber)?;

let state = state
.chains
.get(&chain_id)
.ok_or_else(|| RestError::InvalidChainId)?;

let r = state
.contract
.get_request(state.provider_address, sequence)
Expand All @@ -60,8 +70,10 @@ pub async fn revelation(
}

#[derive(Debug, serde::Serialize, serde::Deserialize, IntoParams)]
#[into_params(parameter_in=Query)]
#[into_params(parameter_in=Path)]
pub struct GetRandomValueQueryParams {
#[param(value_type = String)]
pub chain_id: ChainId,
pub sequence: u64,
}

Expand Down
27 changes: 15 additions & 12 deletions pyth-rng/src/command/generate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use {
crate::{
api::GetRandomValueResponse,
config::GenerateOptions,
ethereum::PythContract,
ethereum::SignablePythContract,
},
std::{
error::Error,
Expand All @@ -12,7 +12,13 @@ use {

/// Run the entire random number generation protocol to produce a random number.
pub async fn generate(opts: &GenerateOptions) -> Result<(), Box<dyn Error>> {
let contract = Arc::new(PythContract::from_opts(&opts.ethereum).await?);
let contract = Arc::new(
SignablePythContract::from_config(
&opts.config.load()?.get_chain_config(&opts.chain_id)?,
&opts.private_key,
)
.await?,
);

let user_randomness = rand::random::<[u8; 32]>();
let provider = opts.provider;
Expand All @@ -27,16 +33,13 @@ pub async fn generate(opts: &GenerateOptions) -> Result<(), Box<dyn Error>> {
);

// Get the committed value from the provider
let client = reqwest::Client::new();
let request_url = client
.get(opts.url.join("/v1/revelation")?)
.query(&[("sequence", sequence_number)])
.build()?;
let resp = client
.execute(request_url)
.await?
.json::<GetRandomValueResponse>()
.await?;
let resp = reqwest::get(opts.url.join(&format!(
"/v1/chains/{}/revelations/{}",
opts.chain_id, sequence_number
))?)
.await?
.json::<GetRandomValueResponse>()
.await?;

println!(
"Retrieved the provider's random value. Server response: {:#?}",
Expand Down
4 changes: 3 additions & 1 deletion pyth-rng/src/command/get_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ use {
/// Get the on-chain request metadata for a provider and sequence number.
pub async fn get_request(opts: &GetRequestOptions) -> Result<(), Box<dyn Error>> {
// Initialize a Provider to interface with the EVM contract.
let contract = Arc::new(PythContract::from_opts(&opts.ethereum).await?);
let contract = Arc::new(PythContract::from_config(
&opts.config.load()?.get_chain_config(&opts.chain_id)?,
)?);

let r = contract
.get_request(opts.provider, opts.sequence)
Expand Down
12 changes: 9 additions & 3 deletions pyth-rng/src/command/register_provider.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use {
crate::{
config::RegisterProviderOptions,
ethereum::PythContract,
ethereum::SignablePythContract,
state::PebbleHashChain,
},
std::{
Expand All @@ -14,11 +14,17 @@ use {
/// hash chain from the configured secret & a newly generated random value.
pub async fn register_provider(opts: &RegisterProviderOptions) -> Result<(), Box<dyn Error>> {
// Initialize a Provider to interface with the EVM contract.
let contract = Arc::new(PythContract::from_opts(&opts.ethereum).await?);
let contract = Arc::new(
SignablePythContract::from_config(
&opts.config.load()?.get_chain_config(&opts.chain_id)?,
&opts.private_key,
)
.await?,
);

// Create a new random hash chain.
let random = rand::random::<[u8; 32]>();
let mut chain = PebbleHashChain::from_config(&opts.randomness, random)?;
let mut chain = PebbleHashChain::from_config(&opts.randomness, &opts.chain_id, random)?;

// Arguments to the contract to register our new provider.
let fee_in_wei = opts.fee;
Expand Down
10 changes: 8 additions & 2 deletions pyth-rng/src/command/request_randomness.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use {
crate::{
config::RequestRandomnessOptions,
ethereum::PythContract,
ethereum::SignablePythContract,
},
std::{
error::Error,
Expand All @@ -10,7 +10,13 @@ use {
};

pub async fn request_randomness(opts: &RequestRandomnessOptions) -> Result<(), Box<dyn Error>> {
let contract = Arc::new(PythContract::from_opts(&opts.ethereum).await?);
let contract = Arc::new(
SignablePythContract::from_config(
&opts.config.load()?.get_chain_config(&opts.chain_id)?,
&opts.private_key,
)
.await?,
);

let user_randomness = rand::random::<[u8; 32]>();
let sequence_number = contract
Expand Down
Loading

0 comments on commit 9604aa4

Please sign in to comment.