Skip to content

Commit 511a5b0

Browse files
author
David Petrov
authored
feat(signer)!: add proxy keys (Commit-Boost#39)
* feat(signer)!: add proxy keys - 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 * chore(clippy): remove unnecessary `clone` * chore(signer): remove `SignerModuleError::UnknownModuleId` not needed anymore since JWTs now uniquely identify the module * feat(docs)!: update with proxy keys * chore(da_commit): add proxy key example * chore: resolve TODO * also, add `rust-toolchain.toml` * chore: fix typo * chore: move dependency to workspace * chore: sync rust version in docs * chore: reexport `SignedProxyDelegation` from prelude * chore: use `fmt::Display` of `ModuleId` in traces * chore: rename field back to `message` * chore: make log level `error` * chore: remove TODO * fix: error log on module startup
1 parent 4fac191 commit 511a5b0

26 files changed

Lines changed: 416 additions & 102 deletions

File tree

.dockerignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1-
target
1+
target
2+
Dockerfile
3+
.dockerignore
4+
.git
5+
.gitignore

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,5 @@ rand = "0.8.5"
7979
dotenvy = "0.15.7"
8080
indexmap = "2.2.6"
8181
lazy_static = "1.5.0"
82+
bimap = { version = "0.6.3", features = ["serde"] }
83+
derive_more = "0.99.18"

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
A new Ethereum validator sidecar focused on standardizing the last mile of communication between validators and third-party protocols.
44

5-
[Docs](https://commit-boost.github.io/commit-boost-client/) |
5+
[Docs](https://commit-boost.github.io/commit-boost-client/) |
66
[Twitter](https://x.com/Commit_Boost)
77

88
## Overview
@@ -51,7 +51,7 @@ async fn main() {
5151
let pubkey = *pubkeys.consensus.first().unwrap();
5252

5353
let datagram = Datagram { data: 42 };
54-
let request = SignRequest::builder(config.id, pubkey).with_msg(&datagram);
54+
let request = SignRequest::builder(pubkey).with_msg(&datagram);
5555
let signature = config
5656
.signer_client
5757
.request_signature(&request)

api/signer-api.yml

Lines changed: 86 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ paths:
1111
summary: Get a list of public keys for which signatures may be requested
1212
tags:
1313
- Signer
14+
security:
15+
- BearerAuth: []
1416
responses:
1517
"200":
1618
description: A list of Bls pubkeys
@@ -35,7 +37,6 @@ paths:
3537
format: hex
3638
pattern: "^0x[a-fA-F0-9]{96}$"
3739
example: "0xa3ffa9241f78279f1af04644cb8c79c2d8f02bcf0e28e2f186f6dcccac0a869c2be441fda50f0dea895cfce2e53f0989"
38-
3940
"500":
4041
description: Internal error
4142
content:
@@ -67,10 +68,6 @@ paths:
6768
schema:
6869
type: object
6970
properties:
70-
id:
71-
description: The module ID
72-
type: string
73-
example: "MY_MODULE_ID"
7471
pubkey:
7572
description: BLS public key of validator
7673
type: string
@@ -99,7 +96,7 @@ paths:
9996
pattern: "^0x[a-fA-F0-9]{192}$"
10097
example: "0xa3ffa9241f78279f1af04644cb8c79c2d8f02bcf0e28e2f186f6dcccac0a869c2be441fda50f0dea895cfce2e53f0989a3ffa9241f78279f1af04644cb8c79c2d8f02bcf0e28e2f186f6dcccac0a869c2be441fda50f0dea895cfce2e53f0989"
10198
"404":
102-
description: Unknown value (pubkey, module id)
99+
description: Unknown value (pubkey, etc.)
103100
content:
104101
application/json:
105102
schema:
@@ -130,6 +127,89 @@ paths:
130127
message:
131128
type: string
132129
example: "Internal error"
130+
131+
/signer/v1/generate_proxy_key:
132+
post:
133+
summary: Request a proxy key be generated for a specific consensus pubkey
134+
tags:
135+
- Signer
136+
security:
137+
- BearerAuth: []
138+
requestBody:
139+
required: true
140+
content:
141+
application/json:
142+
schema:
143+
type: object
144+
properties:
145+
pubkey:
146+
description: a validator BLS public key for which to generate a proxy key
147+
type: string
148+
format: hex
149+
pattern: "^0x[a-fA-F0-9]{96}$"
150+
example: "0xac5e059177afc33263e95d0be0690138b9a1d79a6e19018086a0362e0c30a50bf9e05a08cb44785724d0b2718c5c7118"
151+
responses:
152+
"200":
153+
description: Successs
154+
content:
155+
application/json:
156+
schema:
157+
type: object
158+
properties:
159+
message:
160+
type: object
161+
properties:
162+
delegator:
163+
description: the validator BLS public key for which the proxy key was generated (the same one as requested)
164+
type: string
165+
format: hex
166+
pattern: "^0x[a-fA-F0-9]{96}$"
167+
example: "0xac5e059177afc33263e95d0be0690138b9a1d79a6e19018086a0362e0c30a50bf9e05a08cb44785724d0b2718c5c7118"
168+
proxy:
169+
description: the generated proxy public key
170+
type: string
171+
format: hex
172+
pattern: "^0x[a-fA-F0-9]{96}$"
173+
example: "0x8a481a7a51c430a9bafa64366bc4934f5880f5f1d97646f91680936a53f2a268fdde5369430a2b4bb700c5f82cfbab3f"
174+
signature:
175+
description: The signature of the proxy delegation
176+
type: string
177+
format: hex
178+
pattern: "^0x[a-fA-F0-9]{192}$"
179+
example: "0xabfacf1cd17d80abfc6fa6b8e534ab25cdb1f95a855706ef604672c8695401a84c7834008e57925d4259c551b7c03d1a16f05b082294fadcba802a61a5cccfb5e96dd1dce4c9dac3f6d15254495019146346670be1f374a67cb0cda2aaf72d00"
180+
"404":
181+
description: Unknown value (pubkey, etc.)
182+
content:
183+
application/json:
184+
schema:
185+
type: object
186+
required:
187+
- code
188+
- message
189+
properties:
190+
code:
191+
type: number
192+
example: 404
193+
message:
194+
type: string
195+
example: "Unknown pubkey"
196+
"500":
197+
description: Internal error
198+
content:
199+
application/json:
200+
schema:
201+
type: object
202+
required:
203+
- code
204+
- message
205+
properties:
206+
code:
207+
type: number
208+
example: 500
209+
message:
210+
type: string
211+
example: "Internal error"
212+
133213
components:
134214
securitySchemes:
135215
BearerAuth:

bin/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
pub mod prelude {
22
pub use cb_common::{
33
commit,
4-
commit::request::SignRequest,
4+
commit::request::{SignRequest, SignedProxyDelegation},
55
config::{load_builder_module_config, load_commit_module_config, StartCommitModuleConfig},
66
pbs::{BuilderEvent, BuilderEventClient, OnBuilderApiEvent},
77
utils::{initialize_tracing_log, utcnow_ms, utcnow_ns, utcnow_sec, utcnow_us},

crates/common/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,5 @@ thiserror.workspace = true
4141
eyre.workspace = true
4242
url.workspace = true
4343
rand.workspace = true
44+
bimap.workspace = true
45+
derive_more.workspace = true

crates/common/src/commit/client.rs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@ use reqwest::header::{HeaderMap, HeaderValue, AUTHORIZATION};
66
use serde::{Deserialize, Serialize};
77

88
use super::{
9-
constants::{GET_PUBKEYS_PATH, REQUEST_SIGNATURE_PATH},
9+
constants::{GENERATE_PROXY_KEY_PATH, GET_PUBKEYS_PATH, REQUEST_SIGNATURE_PATH},
1010
error::SignerClientError,
11-
request::SignRequest,
11+
request::{GenerateProxyRequest, SignRequest, SignedProxyDelegation},
1212
};
1313
use crate::DEFAULT_REQUEST_TIMEOUT;
1414

@@ -87,4 +87,27 @@ impl SignerClient {
8787

8888
Ok(signature)
8989
}
90+
91+
pub async fn generate_proxy_key(
92+
&self,
93+
pubkey: BlsPublicKey,
94+
) -> Result<SignedProxyDelegation, SignerClientError> {
95+
let url = format!("{}{}", self.url, GENERATE_PROXY_KEY_PATH);
96+
let request = GenerateProxyRequest::new(pubkey);
97+
let res = self.client.post(&url).json(&request).send().await?;
98+
99+
let status = res.status();
100+
let response_bytes = res.bytes().await?;
101+
102+
if !status.is_success() {
103+
return Err(SignerClientError::FailedRequest {
104+
status: status.as_u16(),
105+
error_msg: String::from_utf8_lossy(&response_bytes).into_owned(),
106+
});
107+
}
108+
109+
let signed_proxy_delegation = serde_json::from_slice(&response_bytes)?;
110+
111+
Ok(signed_proxy_delegation)
112+
}
90113
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
pub const GET_PUBKEYS_PATH: &str = "/signer/v1/get_pubkeys";
22
pub const REQUEST_SIGNATURE_PATH: &str = "/signer/v1/request_signature";
3+
pub const GENERATE_PROXY_KEY_PATH: &str = "/signer/v1/generate_proxy_key";

crates/common/src/commit/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub enum SignerClientError {
66
#[error("invalid header value: {0}")]
77
InvalidHeader(#[from] reqwest::header::InvalidHeaderValue),
88

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

1212
#[error("serde decode error: {0}")]

crates/common/src/commit/request.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,24 +34,22 @@ impl SignedProxyDelegation {
3434

3535
#[derive(Debug, Clone, Serialize, Deserialize)]
3636
pub struct SignRequest {
37-
pub id: String,
3837
pub pubkey: BlsPublicKey,
3938
pub is_proxy: bool,
4039
pub object_root: [u8; 32],
4140
}
4241

4342
impl SignRequest {
4443
pub fn new(
45-
id: impl Into<String>,
4644
pubkey: BlsPublicKey,
4745
is_proxy: bool,
4846
object_root: [u8; 32],
4947
) -> SignRequest {
50-
Self { id: id.into(), pubkey, is_proxy, object_root }
48+
Self { pubkey, is_proxy, object_root }
5149
}
5250

53-
pub fn builder(id: impl Into<String>, pubkey: BlsPublicKey) -> Self {
54-
Self::new(id, pubkey, false, [0; 32])
51+
pub fn builder(pubkey: BlsPublicKey) -> Self {
52+
Self::new(pubkey, false, [0; 32])
5553
}
5654

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

6563
pub fn with_msg(self, msg: &impl TreeHash) -> Self {
66-
Self { object_root: msg.tree_hash_root().0, ..self }
64+
self.with_root(msg.tree_hash_root().0)
65+
}
66+
}
67+
68+
#[derive(Debug, Clone, Serialize, Deserialize)]
69+
pub struct GenerateProxyRequest {
70+
pub pubkey: BlsPublicKey,
71+
}
72+
73+
impl GenerateProxyRequest {
74+
pub fn new(pubkey: BlsPublicKey) -> Self {
75+
GenerateProxyRequest { pubkey }
6776
}
6877
}

0 commit comments

Comments
 (0)