Skip to content

Commit

Permalink
feat(starknet_client): block signature data endpoint (#1548)
Browse files Browse the repository at this point in the history
  • Loading branch information
yair-starkware authored Dec 24, 2023
1 parent 495c79d commit ec822e5
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 2 deletions.
24 changes: 24 additions & 0 deletions crates/starknet_client/src/reader/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use starknet_api::StarknetApiError;
use tracing::{debug, instrument};
use url::Url;

use self::objects::block::BlockSignatureData;
pub use crate::reader::objects::block::{Block, TransactionReceiptsError};
pub use crate::reader::objects::pending_data::PendingData;
pub use crate::reader::objects::state::{
Expand Down Expand Up @@ -97,6 +98,11 @@ pub trait StarknetReader {

// Returns true if the reader is alive.
async fn is_alive(&self) -> bool;

async fn block_signature(
&self,
block_number: BlockNumber,
) -> ReaderClientResult<Option<BlockSignatureData>>;
}

/// A client for the [`Starknet`] feeder gateway.
Expand All @@ -115,6 +121,7 @@ struct StarknetUrls {
get_state_update: Url,
get_pending_data: Url,
feeder_gateway_is_alive: Url,
get_block_signature: Url,
}

const GET_BLOCK_URL: &str = "feeder_gateway/get_block";
Expand All @@ -129,6 +136,7 @@ const PENDING_BLOCK_ID: &str = "pending";
const INCLUDE_BLOCK: &str = "includeBlock";
const FEEDER_GATEWAY_IS_ALIVE: &str = "feeder_gateway/is_alive";
const FEEDER_GATEWAY_ALIVE_RESPONSE: &str = "FeederGateway is alive!";
const GET_BLOCK_SIGNATURE_URL: &str = "feeder_gateway/get_signature";

impl StarknetUrls {
fn new(url_str: &str) -> Result<Self, ClientCreationError> {
Expand Down Expand Up @@ -158,6 +166,7 @@ impl StarknetUrls {
.finish()
.clone(),
feeder_gateway_is_alive: base_url.join(FEEDER_GATEWAY_IS_ALIVE)?,
get_block_signature: base_url.join(GET_BLOCK_SIGNATURE_URL)?,
})
}
}
Expand Down Expand Up @@ -335,6 +344,21 @@ impl StarknetReader for StarknetFeederGatewayClient {
let expected_response = FEEDER_GATEWAY_ALIVE_RESPONSE.to_string();
response.is_ok_and(|response| response == expected_response)
}

#[instrument(skip(self), level = "debug")]
async fn block_signature(
&self,
block_number: BlockNumber,
) -> ReaderClientResult<Option<BlockSignatureData>> {
let mut url = self.urls.get_block_signature.clone();
url.query_pairs_mut().append_pair(BLOCK_NUMBER_QUERY, &block_number.to_string());
let response = self.request_with_retry_url(url).await;
load_object_from_response(
response,
KnownStarknetErrorCode::BlockNotFound,
format!("Failed to get signature for block {block_number:?} from starknet server."),
)
}
}

/// Load an object from a json string response. If there was a StarknetError with
Expand Down
21 changes: 21 additions & 0 deletions crates/starknet_client/src/reader/objects/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use starknet_api::block::{
GasPrice,
};
use starknet_api::core::{ContractAddress, GlobalRoot};
use starknet_api::hash::StarkFelt;
#[cfg(doc)]
use starknet_api::transaction::TransactionOutput as starknet_api_transaction_output;
use starknet_api::transaction::{TransactionHash, TransactionOffsetInBlock};
Expand Down Expand Up @@ -238,3 +239,23 @@ impl From<BlockStatus> for starknet_api::block::BlockStatus {
}
}
}

/// A block signature and the input data used to create it.
#[derive(
Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord,
)]
pub struct BlockSignatureData {
pub block_number: BlockNumber,
pub signature: [StarkFelt; 2],
pub signature_input: BlockSignatureMessage,
}

/// The input data used to create a block signature (Poseidon hash of this data).
#[derive(
Debug, Default, Copy, Clone, Eq, PartialEq, Hash, Deserialize, Serialize, PartialOrd, Ord,
)]
pub struct BlockSignatureMessage {
pub block_hash: BlockHash,
// TODO(yair): Consider renaming GlobalRoot to PatriciaRoot.
pub state_diff_commitment: GlobalRoot,
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,15 @@ use cairo_lang_starknet::casm_contract_class::CasmContractClass;
use indexmap::indexmap;
use mockito::mock;
use pretty_assertions::assert_eq;
use starknet_api::block::BlockNumber;
use starknet_api::core::{ClassHash, ContractAddress, EntryPointSelector, Nonce, PatriciaKey};
use starknet_api::block::{BlockHash, BlockNumber};
use starknet_api::core::{
ClassHash,
ContractAddress,
EntryPointSelector,
GlobalRoot,
Nonce,
PatriciaKey,
};
use starknet_api::deprecated_contract_class::{
ContractClass as DeprecatedContractClass,
ContractClassAbiEntry,
Expand Down Expand Up @@ -40,6 +47,7 @@ use super::{
GET_BLOCK_URL,
GET_STATE_UPDATE_URL,
};
use crate::reader::objects::block::{BlockSignatureData, BlockSignatureMessage};
use crate::test_utils::read_resource::read_resource_file;
use crate::test_utils::retry::get_test_config;

Expand Down Expand Up @@ -523,3 +531,54 @@ async fn compiled_class_by_hash_unserializable() {
)
.await
}

#[tokio::test]
async fn get_block_signature() {
let starknet_client = StarknetFeederGatewayClient::new(
&mockito::server_url(),
None,
NODE_VERSION,
get_test_config(),
)
.unwrap();

let expected_block_signature = BlockSignatureData {
block_number: BlockNumber(20),
signature: [stark_felt!("0x1"), stark_felt!("0x2")],
signature_input: BlockSignatureMessage {
block_hash: BlockHash(stark_felt!("0x20")),
state_diff_commitment: GlobalRoot(stark_felt!("0x1234")),
},
};

let mock_block_signature =
mock("GET", &format!("/feeder_gateway/get_signature?{BLOCK_NUMBER_QUERY}=20")[..])
.with_status(200)
.with_body(serde_json::to_string(&expected_block_signature).unwrap())
.create();

let block_signature = starknet_client.block_signature(BlockNumber(20)).await.unwrap().unwrap();
mock_block_signature.assert();
assert_eq!(block_signature, expected_block_signature);
}

#[tokio::test]
async fn get_block_signature_unknown_block() {
let starknet_client = StarknetFeederGatewayClient::new(
&mockito::server_url(),
None,
NODE_VERSION,
get_test_config(),
)
.unwrap();

let body = r#"{"code": "StarknetErrorCode.BLOCK_NOT_FOUND", "message": "Block number 999999 was not found."}"#;
let mock_no_block =
mock("GET", &format!("/feeder_gateway/get_signature?{BLOCK_NUMBER_QUERY}=999999")[..])
.with_status(400)
.with_body(body)
.create();
let block_signature = starknet_client.block_signature(BlockNumber(999999)).await.unwrap();
mock_no_block.assert();
assert!(block_signature.is_none());
}

0 comments on commit ec822e5

Please sign in to comment.