use miden_node_proto::{DecodeMessage, Verify, generated as proto};
use miden_node_tracing::{debug, miden_instrument, miden_span_record};
use miden_node_utils::limiter::QueryParamNullifierPrefixLimit;
use super::error_codes::SyncNullifiersErrorCode;
use super::{RpcService, check, database_error_to_status, invalid_block_range_to_status};
use crate::{COMPONENT, LOG_TARGET};
#[tonic::async_trait]
impl proto::server::rpc_api::SyncNullifiers for RpcService {
type Input = proto::rpc::DecodedSyncNullifiersRequest;
type Output = proto::rpc::SyncNullifiersResponse;
fn decode(request: proto::rpc::SyncNullifiersRequest) -> tonic::Result<Self::Input> {
request
.decode_fields()
.map_err(|err| SyncNullifiersErrorCode::DeserializationFailed.invalid_argument(err))
}
fn encode(output: Self::Output) -> tonic::Result<proto::rpc::SyncNullifiersResponse> {
Ok(output)
}
#[miden_instrument(
target = COMPONENT,
name = "sync_nullifiers",
err,
)]
async fn handle(
&self,
request: Self::Input,
_metadata: &tonic::metadata::MetadataMap,
_extensions: &tonic::codegen::http::Extensions,
) -> tonic::Result<Self::Output> {
let range = request.block_range;
let nullifiers = request.nullifiers.into_inner();
miden_span_record!(
block_range.from = range.block_from,
block_range.to = range.block_to,
prefix_len = request.prefix_len,
prefixes = nullifiers.as_slice() #[nonstandard]
);
debug!(
target: LOG_TARGET,
"Syncing nullifiers",
block_range.from = range.block_from,
block_range.to = range.block_to,
prefix_len = request.prefix_len,
prefixes = nullifiers.as_slice() #[nonstandard]
);
check::<QueryParamNullifierPrefixLimit>(nullifiers.len())?;
if request.prefix_len != 16 {
return Err(SyncNullifiersErrorCode::InvalidPrefixLength.invalid_argument(format!(
"unsupported prefix length: {} (only 16-bit prefixes are supported)",
request.prefix_len
)));
}
if let Some(&prefix) = nullifiers.iter().find(|&&prefix| prefix > u32::from(u16::MAX)) {
return Err(SyncNullifiersErrorCode::DeserializationFailed.invalid_argument(format!(
"nullifier prefix {prefix} does not fit in the requested prefix length of 16 bits"
)));
}
let block_range = range.verify().map_err(invalid_block_range_to_status)?;
let (chain_tip, (nullifiers, block_num)) = self
.state
.with_view(async |view| {
view.sync_nullifiers(request.prefix_len, nullifiers, block_range)
.await
.map(|nullifiers| (view.tip(), nullifiers))
.map_err(|err| database_error_to_status(&err))
})
.await?;
let nullifiers = nullifiers
.into_iter()
.map(|nullifier_info| proto::rpc::sync_nullifiers_response::NullifierUpdate {
nullifier: Some(nullifier_info.nullifier.as_word().into()),
block_num: nullifier_info.block_num.as_u32(),
})
.collect();
Ok(proto::rpc::SyncNullifiersResponse {
pagination_info: Some(proto::rpc::PaginationInfo {
chain_tip: chain_tip.as_u32(),
block_num: block_num.as_u32(),
}),
nullifiers,
})
}
}