Skip to content

Commit

Permalink
feat(signer)!: add proxy keys
Browse files Browse the repository at this point in the history
- add `generate_proxy_keys` endpoint to the Signer API. Modify the signer client accordingly.

- add a `.dockerignore` file

- remove the need for modules to provide their id in requests. A module's JWT is now solely sufficient to identify the module.
  * `SigningService` now contains jwt <-> module_id in a bidirectional hashmap

- add authentication middleware to the signer service instead of manual auth in the handlers

- introduce `ModuleId` and `Jwt` wrapper types around strings to improve semantics (useful after a couple of mishaps with key <-> value directions across the different maps)
  * see `common::types`

- add example proxy key generation request in `da_commit` module

- small misc changes

- small reformatting
  • Loading branch information
David-Petrov committed Jul 26, 2024
1 parent 5041f16 commit 78d53ed
Show file tree
Hide file tree
Showing 15 changed files with 258 additions and 57 deletions.
5 changes: 5 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
target
Dockerfile
.dockerignore
.git
.gitignore
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,4 @@ rand = "0.8.5"
dotenvy = "0.15.7"
indexmap = "2.2.6"
lazy_static = "1.5.0"
bimap = { version = "0.6.3", features = ["serde"] }
2 changes: 2 additions & 0 deletions crates/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,5 @@ thiserror.workspace = true
eyre.workspace = true
url.workspace = true
rand.workspace = true
bimap.workspace = true
derive_more = "0.99.18"
29 changes: 26 additions & 3 deletions crates/common/src/commit/client.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use std::sync::Arc;

use alloy::rpc::types::beacon::{BlsPublicKey, BlsSignature};
use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
use reqwest::{header::{HeaderMap, HeaderValue, AUTHORIZATION}, StatusCode};
use serde::{Deserialize, Serialize};

use super::{
constants::{GET_PUBKEYS_PATH, REQUEST_SIGNATURE_PATH},
constants::{GENERATE_PROXY_KEY_PATH, GET_PUBKEYS_PATH, REQUEST_SIGNATURE_PATH},
error::SignerClientError,
request::SignRequest,
request::{GenerateProxyRequest, SignRequest, SignedProxyDelegation},
};

#[derive(Debug, Clone, Deserialize, Serialize)]
Expand Down Expand Up @@ -83,4 +83,27 @@ impl SignerClient {

Ok(signature)
}

pub async fn generate_proxy_key(
&self,
pubkey: BlsPublicKey,
) -> Result<SignedProxyDelegation, SignerClientError> {
let url = format!("{}{}", self.url, GENERATE_PROXY_KEY_PATH);
let request = GenerateProxyRequest::new(pubkey);
let res = self.client.post(&url).json(&request).send().await?;

let status = res.status();
let response_bytes = res.bytes().await?;

if !status.is_success() {
return Err(SignerClientError::FailedRequest {
status: status.as_u16(),
error_msg: String::from_utf8_lossy(&response_bytes).into_owned(),
});
}

let signed_proxy_delegation = serde_json::from_slice(&response_bytes)?;

Ok(signed_proxy_delegation)
}
}
1 change: 1 addition & 0 deletions crates/common/src/commit/constants.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
pub const GET_PUBKEYS_PATH: &str = "/signer/v1/get_pubkeys";
pub const REQUEST_SIGNATURE_PATH: &str = "/signer/v1/request_signature";
pub const GENERATE_PROXY_KEY_PATH: &str = "/signer/v1/generate_proxy_key";
2 changes: 1 addition & 1 deletion crates/common/src/commit/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub enum SignerClientError {
#[error("invalid header value: {0}")]
InvalidHeader(#[from] reqwest::header::InvalidHeaderValue),

#[error("failed request: status {status} msg {error_msg}")]
#[error("failed request: status {status}; message: \"{error_msg}\"")]
FailedRequest { status: u16, error_msg: String },

#[error("serde decode error: {0}")]
Expand Down
21 changes: 15 additions & 6 deletions crates/common/src/commit/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,24 +34,22 @@ impl SignedProxyDelegation {

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SignRequest {
pub id: String,
pub pubkey: BlsPublicKey,
pub is_proxy: bool,
pub object_root: [u8; 32],
}

impl SignRequest {
pub fn new(
id: impl Into<String>,
pubkey: BlsPublicKey,
is_proxy: bool,
object_root: [u8; 32],
) -> SignRequest {
Self { id: id.into(), pubkey, is_proxy, object_root }
Self { pubkey, is_proxy, object_root }
}

pub fn builder(id: impl Into<String>, pubkey: BlsPublicKey) -> Self {
Self::new(id, pubkey, false, [0; 32])
pub fn builder(pubkey: BlsPublicKey) -> Self {
Self::new(pubkey, false, [0; 32])
}

pub fn is_proxy(self) -> Self {
Expand All @@ -63,6 +61,17 @@ impl SignRequest {
}

pub fn with_msg(self, msg: &impl TreeHash) -> Self {
Self { object_root: msg.tree_hash_root().0, ..self }
self.with_root(msg.tree_hash_root().0)
}
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenerateProxyRequest {
pub pubkey: BlsPublicKey,
}

impl GenerateProxyRequest {
pub fn new(pubkey: BlsPublicKey) -> Self {
GenerateProxyRequest { pubkey }
}
}
17 changes: 9 additions & 8 deletions crates/common/src/config.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
use std::{collections::HashMap, sync::Arc};

use alloy::primitives::U256;
use bimap::BiHashMap;
use eyre::{eyre, ContextCompat};
use serde::{de::DeserializeOwned, Deserialize, Serialize};

use super::utils::as_eth_str;
use crate::{commit::client::SignerClient, loader::SignerLoader, pbs::RelayEntry, types::Chain};
use crate::{commit::client::SignerClient, loader::SignerLoader, pbs::RelayEntry, types::{Chain, ModuleId, Jwt}};

pub const MODULE_ID_ENV: &str = "CB_MODULE_ID";
pub const MODULE_JWT_ENV: &str = "CB_SIGNER_JWT";
Expand Down Expand Up @@ -49,8 +50,8 @@ fn load_file_from_env<T: DeserializeOwned>(env: &str) -> T {
load_from_file(&path)
}

/// Loads a map of module id -> jwt token from a json env
fn load_jwts() -> HashMap<String, String> {
/// Loads a bidirectional map of module id <-> jwt token from a json env
fn load_jwts() -> BiHashMap<ModuleId, Jwt> {
let jwts = std::env::var(JWTS_ENV).expect(&format!("{JWTS_ENV} is not set"));
serde_json::from_str(&jwts).expect(&format!("Failed to parse jwts: {jwts}"))
}
Expand Down Expand Up @@ -83,7 +84,7 @@ pub struct StartSignerConfig {
pub chain: Chain,
pub loader: SignerLoader,
pub server_port: u16,
pub jwts: HashMap<String, String>,
pub jwts: BiHashMap<ModuleId, Jwt>,
}

impl StartSignerConfig {
Expand Down Expand Up @@ -240,7 +241,7 @@ pub fn load_pbs_custom_config<T: DeserializeOwned>() -> eyre::Result<PbsModuleCo
#[derive(Debug, Deserialize, Serialize)]
pub struct StaticModuleConfig {
/// Unique id of the module
pub id: String,
pub id: ModuleId,
/// Docker image of the module
pub docker_image: String,
}
Expand All @@ -249,7 +250,7 @@ pub struct StaticModuleConfig {
#[derive(Debug)]
pub struct StartModuleConfig<T = ()> {
/// Unique id of the module
pub id: String,
pub id: ModuleId,
/// Chain spec
pub chain: Chain,
/// Signer client to call Signer API
Expand All @@ -264,8 +265,8 @@ pub struct StartModuleConfig<T = ()> {
/// - [MODULE_JWT_ENV] - the jwt token for the module
// TODO: add metrics url here
pub fn load_module_config<T: DeserializeOwned>() -> eyre::Result<StartModuleConfig<T>> {
let module_id = load_env_var_infallible(MODULE_ID_ENV);
let module_jwt = load_env_var_infallible(MODULE_JWT_ENV);
let module_id = ModuleId(load_env_var_infallible(MODULE_ID_ENV));
let module_jwt = Jwt(load_env_var_infallible(MODULE_JWT_ENV));
let signer_server_address = load_env_var_infallible(SIGNER_SERVER_ENV);

#[derive(Debug, Deserialize)]
Expand Down
4 changes: 1 addition & 3 deletions crates/common/src/signature.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,9 +90,7 @@ pub fn sign_builder_message(
secret_key: &SecretKey,
msg: &impl TreeHash,
) -> BlsSignature {
let domain = chain.builder_domain();
let signing_root = compute_signing_root(msg.tree_hash_root().0, domain);
sign_message(secret_key, &signing_root)
sign_builder_root(chain, secret_key, msg.tree_hash_root().0)
}

pub fn sign_builder_root(
Expand Down
12 changes: 12 additions & 0 deletions crates/common/src/types.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use derive_more::{Deref, From, Into, Display};

use serde::{Deserialize, Serialize};

use crate::constants::{
Expand Down Expand Up @@ -43,3 +45,13 @@ impl Chain {
}
}
}

#[derive(Clone, Debug, Display, PartialEq, Eq, Hash, Deref, From, Into, Serialize, Deserialize)]
#[into(owned, ref, ref_mut)]
#[serde(transparent)]
pub struct ModuleId(pub String);

#[derive(Clone, Debug, Display, PartialEq, Eq, Hash, Deref, From, Into, Serialize, Deserialize)]
#[into(owned, ref, ref_mut)]
#[serde(transparent)]
pub struct Jwt(pub String);
2 changes: 2 additions & 0 deletions crates/signer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,5 @@ thiserror.workspace = true
eyre.workspace = true
rand.workspace = true
uuid.workspace = true
bimap.workspace = true
lazy_static.workspace = true
3 changes: 2 additions & 1 deletion crates/signer/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use axum::{
http::StatusCode,
response::{IntoResponse, Response},
};
use cb_common::types::ModuleId;
use thiserror::Error;

#[derive(Debug, Error)]
Expand All @@ -11,7 +12,7 @@ pub enum SignerModuleError {
Unauthorized,

#[error("unknown module id: {0}")]
UnknownModuleId(String),
UnknownModuleId(ModuleId),

#[error("unknown consensus signer: {0}")]
UnknownConsensusSigner(BlsPublicKey),
Expand Down
Loading

0 comments on commit 78d53ed

Please sign in to comment.