use core::convert::TryFrom;
use miden_tx::utils::serde::{
ByteReader,
ByteWriter,
Deserializable,
DeserializationError,
Serializable,
};
use crate::rpc::RpcEndpoint;
use crate::rpc::errors::RpcConversionError;
use crate::rpc::generated::rpc as proto;
pub(crate) const RPC_LIMITS_STORE_SETTING: &str = "rpc_limits";
const DEFAULT_NOTE_IDS_LIMIT: u32 = 100;
const DEFAULT_NULLIFIERS_LIMIT: u32 = 1000;
const DEFAULT_ACCOUNT_IDS_LIMIT: u32 = 1000;
const DEFAULT_NOTE_TAGS_LIMIT: u32 = 1000;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RpcLimits {
pub note_ids_limit: u32,
pub nullifiers_limit: u32,
pub account_ids_limit: u32,
pub note_tags_limit: u32,
}
impl Default for RpcLimits {
fn default() -> Self {
Self {
note_ids_limit: DEFAULT_NOTE_IDS_LIMIT,
nullifiers_limit: DEFAULT_NULLIFIERS_LIMIT,
account_ids_limit: DEFAULT_ACCOUNT_IDS_LIMIT,
note_tags_limit: DEFAULT_NOTE_TAGS_LIMIT,
}
}
}
impl Serializable for RpcLimits {
fn write_into<W: ByteWriter>(&self, target: &mut W) {
self.note_ids_limit.write_into(target);
self.nullifiers_limit.write_into(target);
self.account_ids_limit.write_into(target);
self.note_tags_limit.write_into(target);
}
}
impl Deserializable for RpcLimits {
fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
Ok(Self {
note_ids_limit: u32::read_from(source)?,
nullifiers_limit: u32::read_from(source)?,
account_ids_limit: u32::read_from(source)?,
note_tags_limit: u32::read_from(source)?,
})
}
}
fn get_param(
proto: &proto::RpcLimits,
endpoint: RpcEndpoint,
param: &'static str,
) -> Result<u32, RpcConversionError> {
let ep = proto.endpoints.get(endpoint.proto_name()).ok_or(
RpcConversionError::MissingFieldInProtobufRepresentation {
entity: "RpcLimits",
field_name: param,
},
)?;
let limit = ep.parameters.get(param).ok_or(
RpcConversionError::MissingFieldInProtobufRepresentation {
entity: "RpcLimits",
field_name: param,
},
)?;
Ok(*limit)
}
impl TryFrom<proto::RpcLimits> for RpcLimits {
type Error = RpcConversionError;
fn try_from(proto: proto::RpcLimits) -> Result<Self, Self::Error> {
Ok(Self {
note_ids_limit: get_param(&proto, RpcEndpoint::GetNotesById, "note_id")?,
nullifiers_limit: get_param(&proto, RpcEndpoint::CheckNullifiers, "nullifier")
.or_else(|_| get_param(&proto, RpcEndpoint::SyncNullifiers, "nullifier"))?,
account_ids_limit: get_param(&proto, RpcEndpoint::SyncTransactions, "account_id")?,
note_tags_limit: get_param(&proto, RpcEndpoint::SyncNotes, "note_tag")?,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn rpc_limits_serialization_roundtrip() {
let original = RpcLimits {
note_ids_limit: 100,
nullifiers_limit: 1000,
account_ids_limit: 1000,
note_tags_limit: 1000,
};
let bytes = original.to_bytes();
let deserialized = RpcLimits::read_from_bytes(&bytes).expect("deserialization failed");
assert_eq!(original, deserialized);
}
}