Skip to content

Commit 32cf944

Browse files
authored
refactor: remove pagination from SyncChainMMR RPC (#1682)
1 parent 21a84c5 commit 32cf944

9 files changed

Lines changed: 46 additions & 91 deletions

File tree

bin/stress-test/src/store/mod.rs

Lines changed: 7 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -439,9 +439,7 @@ pub async fn bench_sync_chain_mmr(
439439

440440
let request = |_| {
441441
let mut client = store_client.clone();
442-
tokio::spawn(async move {
443-
sync_chain_mmr_paginated(&mut client, chain_tip, block_range_size).await
444-
})
442+
tokio::spawn(async move { sync_chain_mmr(&mut client, chain_tip, block_range_size).await })
445443
};
446444

447445
let results = stream::iter(0..iterations)
@@ -456,77 +454,34 @@ pub async fn bench_sync_chain_mmr(
456454
print_summary(&timers_accumulator);
457455

458456
let total_runs = results.len();
459-
let paginated_runs = results.iter().filter(|r| r.pages > 1).count();
460-
#[expect(clippy::cast_precision_loss)]
461-
let pagination_rate = if total_runs > 0 {
462-
(paginated_runs as f64 / total_runs as f64) * 100.0
463-
} else {
464-
0.0
465-
};
466-
#[expect(clippy::cast_precision_loss)]
467-
let avg_pages = if total_runs > 0 {
468-
results.iter().map(|r| r.pages as f64).sum::<f64>() / total_runs as f64
469-
} else {
470-
0.0
471-
};
472457

473458
println!("Pagination statistics:");
474459
println!(" Total runs: {total_runs}");
475-
println!(" Runs triggering pagination: {paginated_runs}");
476-
println!(" Pagination rate: {pagination_rate:.2}%");
477-
println!(" Average pages per run: {avg_pages:.2}");
478460
}
479461

480462
/// Sends a single `sync_chain_mmr` request to the store and returns a tuple with:
481463
/// - the elapsed time.
482464
/// - the response.
483-
pub async fn sync_chain_mmr(
465+
async fn sync_chain_mmr(
484466
api_client: &mut RpcClient<InterceptedService<Channel, OtelInterceptor>>,
485467
block_from: u32,
486468
block_to: u32,
487-
) -> (Duration, proto::rpc::SyncChainMmrResponse) {
469+
) -> SyncChainMmrRun {
488470
let sync_request = proto::rpc::SyncChainMmrRequest {
489471
block_range: Some(proto::rpc::BlockRange { block_from, block_to: Some(block_to) }),
490472
};
491473

492474
let start = Instant::now();
493475
let response = api_client.sync_chain_mmr(sync_request).await.unwrap();
494-
(start.elapsed(), response.into_inner())
476+
let elapsed = start.elapsed();
477+
let response = response.into_inner();
478+
let _mmr_delta = response.mmr_delta.expect("mmr_delta should exist");
479+
SyncChainMmrRun { duration: elapsed }
495480
}
496481

497482
#[derive(Clone)]
498483
struct SyncChainMmrRun {
499484
duration: Duration,
500-
pages: usize,
501-
}
502-
503-
async fn sync_chain_mmr_paginated(
504-
api_client: &mut RpcClient<InterceptedService<Channel, OtelInterceptor>>,
505-
chain_tip: u32,
506-
block_range_size: u32,
507-
) -> SyncChainMmrRun {
508-
let mut total_duration = Duration::default();
509-
let mut pages = 0usize;
510-
let mut next_block_from = 0u32;
511-
512-
loop {
513-
let target_block_to = next_block_from.saturating_add(block_range_size).min(chain_tip);
514-
let (elapsed, response) =
515-
sync_chain_mmr(api_client, next_block_from, target_block_to).await;
516-
total_duration += elapsed;
517-
pages += 1;
518-
519-
let pagination_info = response.pagination_info.expect("pagination_info should exist");
520-
let _mmr_delta = response.mmr_delta.expect("mmr_delta should exist");
521-
522-
if pagination_info.block_num >= pagination_info.chain_tip {
523-
break;
524-
}
525-
526-
next_block_from = pagination_info.block_num;
527-
}
528-
529-
SyncChainMmrRun { duration: total_duration, pages }
530485
}
531486

532487
// LOAD STATE

crates/proto/src/generated/rpc.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -442,11 +442,11 @@ pub struct SyncChainMmrRequest {
442442
/// Represents the result of syncing chain MMR.
443443
#[derive(Clone, PartialEq, ::prost::Message)]
444444
pub struct SyncChainMmrResponse {
445-
/// Pagination information.
445+
/// For which block range the MMR delta is returned.
446446
#[prost(message, optional, tag = "1")]
447-
pub pagination_info: ::core::option::Option<PaginationInfo>,
447+
pub block_range: ::core::option::Option<BlockRange>,
448448
/// Data needed to update the partial MMR from `request.block_range.block_from + 1` to
449-
/// `pagination_info.block_num`.
449+
/// `response.block_range.block_to` or the chain tip.
450450
#[prost(message, optional, tag = "2")]
451451
pub mmr_delta: ::core::option::Option<super::primitives::MmrDelta>,
452452
}
@@ -1052,6 +1052,7 @@ pub mod api_client {
10521052
.insert(GrpcMethod::new("rpc.Api", "SyncAccountStorageMaps"));
10531053
self.inner.unary(req, path, codec).await
10541054
}
1055+
/// Returns MMR delta needed to synchronize the chain MMR within the requested block range.
10551056
pub async fn sync_chain_mmr(
10561057
&mut self,
10571058
request: impl tonic::IntoRequest<super::SyncChainMmrRequest>,
@@ -1236,6 +1237,7 @@ pub mod api_server {
12361237
tonic::Response<super::SyncAccountStorageMapsResponse>,
12371238
tonic::Status,
12381239
>;
1240+
/// Returns MMR delta needed to synchronize the chain MMR within the requested block range.
12391241
async fn sync_chain_mmr(
12401242
&self,
12411243
request: tonic::Request<super::SyncChainMmrRequest>,

crates/rpc/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ The full gRPC method definitions can be found in the [proto](../proto/README.md)
2525
- [SyncAccountVault](#SyncAccountVault)
2626
- [SyncNotes](#syncnotes)
2727
- [SyncAccountStorageMaps](#syncaccountstoragemaps)
28+
- [SyncChainMmr](#syncchainmmr)
2829
- [SyncTransactions](#synctransactions)
2930

3031
<!--toc:end-->
@@ -236,6 +237,14 @@ When storage map synchronization fails, detailed error information is provided t
236237

237238
---
238239

240+
### SyncChainMmr
241+
242+
Returns MMR delta information needed to synchronize the chain MMR within a block range.
243+
244+
Caller specifies the `block_range`, starting from the last block already represented in its local MMR. The response contains the MMR delta for the requested range along with pagination info so the caller can continue syncing until the chain tip.
245+
246+
---
247+
239248
### SyncTransactions
240249

241250
Returns transaction records for specific accounts within a block range.

crates/rpc/src/tests.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -559,10 +559,6 @@ async fn sync_chain_mmr_returns_delta() {
559559
let response = rpc_client.sync_chain_mmr(request).await.expect("sync_chain_mmr should succeed");
560560
let response = response.into_inner();
561561

562-
let pagination_info = response.pagination_info.expect("pagination_info should exist");
563-
assert_eq!(pagination_info.chain_tip, 0);
564-
assert_eq!(pagination_info.block_num, 0);
565-
566562
let mmr_delta = response.mmr_delta.expect("mmr_delta should exist");
567563
assert_eq!(mmr_delta.forest, 0);
568564
assert!(mmr_delta.data.is_empty());

crates/store/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ The full gRPC API can be found [here](../../proto/proto/store.proto).
5555
- [SyncAccountVault](#syncaccountvault)
5656
- [SyncNotes](#syncnotes)
5757
- [SyncAccountStorageMaps](#syncaccountstoragemaps)
58+
- [SyncChainMmr](#syncchainmmr)
5859
- [SyncTransactions](#synctransactions)
5960
<!--toc:end-->
6061

@@ -249,6 +250,14 @@ When storage map synchronization fails, detailed error information is provided t
249250

250251
---
251252

253+
### SyncChainMmr
254+
255+
Returns MMR delta information needed to synchronize the chain MMR within a block range.
256+
257+
Caller specifies the `block_range`, starting from the last block already represented in its local MMR. The response contains the MMR delta for the requested range and the returned `block_range` reflects the last block included, which may be the chain tip.
258+
259+
---
260+
252261
### SyncTransactions
253262

254263
Returns transaction records for specific accounts within a block range.

crates/store/src/server/rpc_api.rs

Lines changed: 5 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,6 @@ impl rpc_server::Rpc for StoreApi {
158158
&self,
159159
request: Request<proto::rpc::SyncChainMmrRequest>,
160160
) -> Result<Response<proto::rpc::SyncChainMmrResponse>, Status> {
161-
// TODO find a reasonable upper boundary
162-
const MAX_BLOCKS: u32 = 1 << 20;
163-
164161
let request = request.into_inner();
165162
let chain_tip = self.state.latest_block_num().await;
166163

@@ -183,23 +180,13 @@ impl rpc_server::Rpc for StoreApi {
183180
}))?;
184181
}
185182
let block_range = block_from..=block_to;
186-
let len = 1 + block_range.end().as_u32() - block_range.start().as_u32();
187-
let trimmed_block_range = if len > MAX_BLOCKS {
188-
block_from..=BlockNumber::from(block_from.as_u32() + MAX_BLOCKS)
189-
} else {
190-
block_range
191-
};
192-
193-
let mmr_delta = self
194-
.state
195-
.sync_chain_mmr(trimmed_block_range.clone())
196-
.await
197-
.map_err(internal_error)?;
183+
let mmr_delta =
184+
self.state.sync_chain_mmr(block_range.clone()).await.map_err(internal_error)?;
198185

199186
Ok(Response::new(proto::rpc::SyncChainMmrResponse {
200-
pagination_info: Some(proto::rpc::PaginationInfo {
201-
chain_tip: chain_tip.as_u32(),
202-
block_num: trimmed_block_range.end().as_u32(),
187+
block_range: Some(proto::rpc::BlockRange {
188+
block_from: block_range.start().as_u32(),
189+
block_to: Some(block_range.end().as_u32()),
203190
}),
204191
mmr_delta: Some(mmr_delta.into()),
205192
}))

crates/utils/src/limiter.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,6 @@ impl QueryParamLimiter for QueryParamBlockLimit {
120120
const LIMIT: usize = GENERAL_REQUEST_LIMIT;
121121
}
122122

123-
/// Used for the following RPC endpoints:
124-
/// * `sync_chain_mmr`
125-
///
126-
/// Capped at 1000 blocks to keep MMR deltas within the 4 MB payload budget.
127-
pub struct QueryParamBlockRangeLimit;
128-
impl QueryParamLimiter for QueryParamBlockRangeLimit {
129-
const PARAM_NAME: &str = "block_range";
130-
const LIMIT: usize = GENERAL_REQUEST_LIMIT;
131-
}
132-
133123
/// Used for the following RPC endpoints
134124
/// * `get_account`
135125
///

docs/external/src/rpc.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ The gRPC service definition can be found in the Miden node's `proto` [directory]
2323
- [SyncAccountVault](#syncaccountvault)
2424
- [SyncNotes](#syncnotes)
2525
- [SyncAccountStorageMaps](#syncaccountstoragemaps)
26+
- [SyncChainMmr](#syncchainmmr)
2627
- [SyncTransactions](#synctransactions)
2728
- [Status](#status)
2829

@@ -216,6 +217,12 @@ Caller specifies the `account_id` of the public account and the block range (`bl
216217

217218
This endpoint enables clients to maintain an updated view of account storage.
218219

220+
### SyncChainMmr
221+
222+
Returns MMR delta information needed to synchronize the chain MMR within a block range.
223+
224+
Caller specifies the `block_range`, starting from the last block already represented in its local MMR. The response contains the MMR delta for the requested range, but at most to (including) the chain tip.
225+
219226
### SyncTransactions
220227

221228
Returns transaction records for specific accounts within a block range.

proto/proto/rpc.proto

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ service Api {
103103
// Returns storage map updates for specified account and storage slots within a block range.
104104
rpc SyncAccountStorageMaps(SyncAccountStorageMapsRequest) returns (SyncAccountStorageMapsResponse) {}
105105

106+
// Returns MMR delta needed to synchronize the chain MMR within the requested block range.
106107
rpc SyncChainMmr(SyncChainMmrRequest) returns (SyncChainMmrResponse) {}
107108
}
108109

@@ -494,11 +495,10 @@ message SyncChainMmrRequest {
494495

495496
// Represents the result of syncing chain MMR.
496497
message SyncChainMmrResponse {
497-
// Pagination information.
498-
PaginationInfo pagination_info = 1;
499-
498+
// For which block range the MMR delta is returned.
499+
BlockRange block_range = 1;
500500
// Data needed to update the partial MMR from `request.block_range.block_from + 1` to
501-
// `pagination_info.block_num`.
501+
// `response.block_range.block_to` or the chain tip.
502502
primitives.MmrDelta mmr_delta = 2;
503503
}
504504

0 commit comments

Comments
 (0)