[fortuna] support multiple random value encodings (#1129)

This commit is contained in:
Jayant Krishnamurthy 2023-11-01 12:40:21 -07:00 committed by GitHub
parent f36e868ef6
commit 46b597e653
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 194 additions and 9 deletions

126
fortuna/Cargo.lock generated
View File

@ -58,6 +58,21 @@ dependencies = [
"memchr",
]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]]
name = "android_system_properties"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
dependencies = [
"libc",
]
[[package]]
name = "anstream"
version = "0.6.4"
@ -511,7 +526,11 @@ version = "0.4.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
dependencies = [
"android-tzdata",
"iana-time-zone",
"num-traits",
"serde",
"windows-targets",
]
[[package]]
@ -750,6 +769,41 @@ dependencies = [
"cipher",
]
[[package]]
name = "darling"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
dependencies = [
"darling_core",
"darling_macro",
]
[[package]]
name = "darling_core"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn 2.0.38",
]
[[package]]
name = "darling_macro"
version = "0.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
dependencies = [
"darling_core",
"quote",
"syn 2.0.38",
]
[[package]]
name = "data-encoding"
version = "2.4.0"
@ -771,6 +825,9 @@ name = "deranged"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946"
dependencies = [
"serde",
]
[[package]]
name = "derive_more"
@ -1407,6 +1464,7 @@ dependencies = [
"serde",
"serde_json",
"serde_qs",
"serde_with",
"serde_yaml",
"sha3",
"tokio",
@ -1787,6 +1845,35 @@ dependencies = [
"tokio-native-tls",
]
[[package]]
name = "iana-time-zone"
version = "0.1.58"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
dependencies = [
"android_system_properties",
"core-foundation-sys",
"iana-time-zone-haiku",
"js-sys",
"wasm-bindgen",
"windows-core",
]
[[package]]
name = "iana-time-zone-haiku"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [
"cc",
]
[[package]]
name = "ident_case"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
[[package]]
name = "idna"
version = "0.4.0"
@ -1855,6 +1942,7 @@ checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"hashbrown 0.12.3",
"serde",
]
[[package]]
@ -3270,6 +3358,35 @@ dependencies = [
"serde",
]
[[package]]
name = "serde_with"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
dependencies = [
"base64 0.21.4",
"chrono",
"hex",
"indexmap 1.9.3",
"indexmap 2.0.2",
"serde",
"serde_json",
"serde_with_macros",
"time",
]
[[package]]
name = "serde_with_macros"
version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788"
dependencies = [
"darling",
"proc-macro2",
"quote",
"syn 2.0.38",
]
[[package]]
name = "serde_yaml"
version = "0.9.25"
@ -4263,6 +4380,15 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-core"
version = "0.51.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
dependencies = [
"windows-targets",
]
[[package]]
name = "windows-sys"
version = "0.48.0"

View File

@ -20,6 +20,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_with = { version = "3.4.0", features = ["hex", "base64"] }
serde_yaml = "0.9.25"
sha3 = "0.10.8"
tokio = { version = "1.33.0", features = ["full"] }

View File

@ -8,18 +8,19 @@ use {
axum::{
extract::{
Path,
Query,
State,
},
Json,
},
pythnet_sdk::wire::array,
serde_with::serde_as,
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 and blockchain.
///
/// Given a sequence number, retrieve the corresponding random value that this provider has committed to.
@ -34,11 +35,12 @@ responses(
(status = 200, description = "Random value successfully retrieved", body = GetRandomValueResponse),
(status = 403, description = "Random value cannot currently be retrieved", body = String)
),
params(GetRandomValueQueryParams)
params(RevelationPathParams, RevelationQueryParams)
)]
pub async fn revelation(
State(state): State<crate::api::ApiState>,
Path(GetRandomValueQueryParams { chain_id, sequence }): Path<GetRandomValueQueryParams>,
Path(RevelationPathParams { chain_id, sequence }): Path<RevelationPathParams>,
Query(RevelationQueryParams { encoding }): Query<RevelationQueryParams>,
) -> Result<Json<GetRandomValueResponse>, RestError> {
state
.metrics
@ -70,8 +72,10 @@ pub async fn revelation(
.state
.reveal(sequence)
.map_err(|_| RestError::Unknown)?;
let encoded_value = Blob::new(encoding.unwrap_or(BinaryEncoding::Hex), value.clone());
Ok(Json(GetRandomValueResponse {
value: (*value).clone(),
value: encoded_value,
}))
} else {
Err(RestError::NoPendingRequest)
@ -80,15 +84,67 @@ pub async fn revelation(
#[derive(Debug, serde::Serialize, serde::Deserialize, IntoParams)]
#[into_params(parameter_in=Path)]
pub struct GetRandomValueQueryParams {
pub struct RevelationPathParams {
#[param(value_type = String)]
pub chain_id: ChainId,
pub sequence: u64,
}
#[derive(Debug, serde::Serialize, serde::Deserialize, IntoParams)]
#[into_params(parameter_in=Query)]
pub struct RevelationQueryParams {
pub encoding: Option<BinaryEncoding>,
}
#[derive(Debug, serde::Serialize, serde::Deserialize, ToSchema)]
#[serde(rename_all = "kebab-case")]
pub enum BinaryEncoding {
#[serde(rename = "hex")]
Hex,
#[serde(rename = "base64")]
Base64,
#[serde(rename = "array")]
Array,
}
#[derive(Debug, serde::Serialize, serde::Deserialize, ToSchema)]
pub struct GetRandomValueResponse {
// TODO: choose serialization format
#[serde(with = "array")]
pub value: [u8; 32],
pub value: Blob,
}
#[serde_as]
#[derive(Debug, serde::Serialize, serde::Deserialize, ToSchema)]
#[serde(tag = "encoding", rename_all = "kebab-case")]
pub enum Blob {
Hex {
#[serde_as(as = "serde_with::hex::Hex")]
data: [u8; 32],
},
Base64 {
#[serde_as(as = "serde_with::base64::Base64")]
data: [u8; 32],
},
Array {
#[serde(with = "array")]
data: [u8; 32],
},
}
impl Blob {
pub fn new(encoding: BinaryEncoding, data: [u8; 32]) -> Blob {
match encoding {
BinaryEncoding::Hex => Blob::Hex { data },
BinaryEncoding::Base64 => Blob::Base64 { data },
BinaryEncoding::Array => Blob::Array { data },
}
}
pub fn data(&self) -> &[u8; 32] {
match self {
Blob::Hex { data } => data,
Blob::Base64 { data } => data,
Blob::Array { data } => data,
}
}
}

View File

@ -45,10 +45,10 @@ pub async fn generate(opts: &GenerateOptions) -> Result<()> {
.await?;
tracing::info!(
response = base64_standard_engine.encode(resp.value),
response = base64_standard_engine.encode(resp.value.data()),
"Retrieved the provider's random value.",
);
let provider_randomness = resp.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

View File

@ -38,6 +38,8 @@ pub async fn run(opts: &RunOptions) -> Result<()> {
components(
schemas(
crate::api::GetRandomValueResponse,
crate::api::Blob,
crate::api::BinaryEncoding,
)
),
tags(