Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: deserialize signed builder bid with proofs #11

Merged
merged 2 commits into from
Oct 7, 2024
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
49 changes: 25 additions & 24 deletions crates/api/src/proposer/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,12 @@ use helix_common::{
proposer_api::{GetPayloadResponse, ValidatorRegistrationInfo},
},
chain_info::{ChainInfo, Network},
proofs::InclusionProofs,
signed_proposal::VersionedSignedProposal,
try_execution_header_from_payload, validator_preferences,
versioned_payload::PayloadAndBlobs,
BidRequest, Filtering, GetHeaderTrace, GetPayloadTrace, RegisterValidatorsTrace,
ValidatorPreferences,
proofs::BidWithProofs,
proofs::InclusionProofs,
};
use helix_database::DatabaseService;
use helix_datastore::{error::AuctioneerError, Auctioneer};
Expand Down Expand Up @@ -441,16 +440,17 @@ where
}
}

/// Retrieves the best bid header (with inclusion proof) for the specified slot, parent hash, and public key.
///
/// Retrieves the best bid header (with inclusion proof) for the specified slot, parent hash,
/// and public key.
///
/// This function accepts a slot number, parent hash and public_key.
/// 1. Validates that the request's slot is not older than the head slot.
/// 2. Validates the request timestamp to ensure it's not too late.
/// 3. Fetches the best bid for the given parameters from the auctioneer.
/// 4. Fetches the inclusion proof for the best bid.
///
///
/// The function returns a JSON response containing the best bid and inclusion proofs if found.
///
///
/// Implements this API: <https://docs.boltprotocol.xyz/api/builder#get_header_with_proofs>
pub async fn get_header_with_proofs(
Extension(proposer_api): Extension<Arc<ProposerApi<A, DB, M, G>>>,
Expand Down Expand Up @@ -496,7 +496,7 @@ where
info!(request_id = %request_id, trace = ?trace, "best bid fetched");

match get_best_bid_res {
Ok(Some(bid)) => {
Ok(Some(mut bid)) => {
if bid.value() == U256::ZERO {
warn!(request_id = %request_id, "best bid value is 0");
return Err(ProposerApiError::BidValueZero);
Expand All @@ -505,19 +505,20 @@ where
// Get inclusion proofs
let proofs = proposer_api
.get_inclusion_proof(
slot,
&bid_request.public_key,
bid.block_hash(),
&request_id)
.await;
slot,
&bid_request.public_key,
bid.block_hash(),
&request_id,
)
.await;

info!(
request_id = %request_id,
value = ?bid.value(),
block_hash = ?bid.block_hash(),
"delivering bid with proofs",
);

// Save trace to DB
proposer_api
.save_get_header_call(
Expand All @@ -529,12 +530,14 @@ where
request_id,
)
.await;


// Attach the proofs to the bid before sending it back
if let Some(proofs) = proofs {
bid.set_inclusion_proofs(proofs);
}

// Return header with proofs
Ok(axum::Json(BidWithProofs {
bid,
proofs,
}))
Ok(axum::Json(bid))
}
Ok(None) => {
warn!(request_id = %request_id, "no bid found");
Expand Down Expand Up @@ -955,8 +958,8 @@ where
/// - Only allows requests for the current slot until a certain cutoff time.
fn validate_bid_request_time(&self, bid_request: &BidRequest) -> Result<(), ProposerApiError> {
let curr_timestamp_ms = get_millis_timestamp()? as i64;
let slot_start_timestamp = self.chain_info.genesis_time_in_secs
+ (bid_request.slot * self.chain_info.seconds_per_slot);
let slot_start_timestamp = self.chain_info.genesis_time_in_secs +
(bid_request.slot * self.chain_info.seconds_per_slot);
let ms_into_slot = curr_timestamp_ms.saturating_sub((slot_start_timestamp * 1000) as i64);

if ms_into_slot > GET_HEADER_REQUEST_CUTOFF_MS {
Expand Down Expand Up @@ -1165,10 +1168,8 @@ where
bid_block_hash: &ByteVector<32>,
request_id: &Uuid,
) -> Option<InclusionProofs> {
let inclusion_proof = self
.auctioneer
.get_inclusion_proof(slot, public_key, bid_block_hash)
.await;
let inclusion_proof =
self.auctioneer.get_inclusion_proof(slot, public_key, bid_block_hash).await;
match inclusion_proof {
Ok(Some(proof)) => Some(proof),
Ok(None) => {
Expand Down
73 changes: 38 additions & 35 deletions crates/api/src/proposer/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@ pub fn gen_signed_vr() -> SignedValidatorRegistration {
mod proposer_api_tests {
// +++ IMPORTS +++
use crate::{
gossiper::{mock_gossiper::MockGossiper, types::GossipedMessage}, proposer::{
gossiper::{mock_gossiper::MockGossiper, types::GossipedMessage},
proposer::{
api::{get_nanos_timestamp, ProposerApi},
PATH_GET_PAYLOAD, PATH_PROPOSER_API,
}, test_utils::proposer_api_app
},
test_utils::proposer_api_app,
};

use ethereum_consensus::{
Expand All @@ -59,8 +61,8 @@ mod proposer_api_tests {
builder_api::BuilderGetValidatorsResponseEntry, proposer_api::ValidatorRegistrationInfo,
},
capella::{self},
deneb::{self},
chain_info::ChainInfo,
deneb::{self},
versioned_payload::PayloadAndBlobs,
SignedBuilderBid, ValidatorPreferences,
};
Expand Down Expand Up @@ -258,10 +260,13 @@ mod proposer_api_tests {
}

fn get_signed_builder_bid(value: U256) -> SignedBuilderBid {
SignedBuilderBid::Capella(capella::SignedBuilderBid {
message: helix_common::eth::capella::BuilderBid { value, ..Default::default() },
..Default::default()
})
SignedBuilderBid::Capella(
capella::SignedBuilderBid {
message: helix_common::eth::capella::BuilderBid { value, ..Default::default() },
..Default::default()
},
None,
)
}

fn get_blinded_beacon_block_body() -> BlindedBeaconBlockBody {
Expand Down Expand Up @@ -993,19 +998,23 @@ mod proposer_api_tests {
let (_gossip_sender, gossip_receiver) = channel::<GossipedMessage>(32);
let auctioneer = Arc::new(MockAuctioneer::default());

let prop_api =
ProposerApi::<MockAuctioneer, MockDatabaseService, MockMultiBeaconClient, MockGossiper>::new(
auctioneer.clone(),
Arc::new(MockDatabaseService::default()),
Arc::new(MockGossiper::new().unwrap()),
vec![],
Arc::new(MockMultiBeaconClient::default()),
Arc::new(ChainInfo::for_holesky()),
slot_update_sender.clone(),
Arc::new(ValidatorPreferences::default()),
0,
gossip_receiver,
);
let prop_api = ProposerApi::<
MockAuctioneer,
MockDatabaseService,
MockMultiBeaconClient,
MockGossiper,
>::new(
auctioneer.clone(),
Arc::new(MockDatabaseService::default()),
Arc::new(MockGossiper::new().unwrap()),
vec![],
Arc::new(MockMultiBeaconClient::default()),
Arc::new(ChainInfo::for_holesky()),
slot_update_sender.clone(),
Arc::new(ValidatorPreferences::default()),
0,
gossip_receiver,
);

let mut x = gen_signed_vr();

Expand All @@ -1014,17 +1023,16 @@ mod proposer_api_tests {

#[test]
fn test_verify_signed_blinded_block_signature_from_file_deneb() {

let mut current_dir = std::env::current_dir().expect("Failed to get current directory");
if !current_dir.ends_with("api") {
current_dir.push("crates/api/");
}
current_dir.push("test_data/signed_blinded_beacon_block_deneb.json");
let req_payload_bytes =
load_bytes(current_dir.to_str().expect("Failed to convert path to string"));
if !current_dir.ends_with("api") {
current_dir.push("crates/api/");
}
current_dir.push("test_data/signed_blinded_beacon_block_deneb.json");
let req_payload_bytes =
load_bytes(current_dir.to_str().expect("Failed to convert path to string"));

let mut decoded_submission: SignedBlindedBeaconBlock =
serde_json::from_slice(&req_payload_bytes).unwrap();
let mut decoded_submission: SignedBlindedBeaconBlock =
serde_json::from_slice(&req_payload_bytes).unwrap();

let chain_info = ChainInfo::for_holesky();
let slot = decoded_submission.message().slot();
Expand All @@ -1043,18 +1051,13 @@ mod proposer_api_tests {
);

match result {
Ok(_) => {

}
Ok(_) => {}
Err(e) => {
println!("Error: {:?}", e);
}

}
}
_ => {}

}

}
}
Loading