fix(api): give NEAR backfills every other turn instead of none
The bridge's mint scan sat with its backfill stalled — 118,898 blocks between gargravarr's oldest and where it started, unread and not moving — because every NEAR scan went back only once it was level with the tip. A forward pass takes longer than NEAR's 0.6 s block, so a live scan is always a block or two behind and the backward turn never came. #44's example deposit was waiting on exactly that stretch. The four NEAR scans (bridge mints, intents, intents flows, pool calls) now alternate while history remains. Forward runs at half pace only while a backfill is pending, and every scan here keeps up with the tip at that. Refs #44 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015pkwBsR54NRmZyU4QVhvfj
This commit is contained in:
@@ -143,6 +143,7 @@ async fn mints(
|
||||
) {
|
||||
let id = chain.id();
|
||||
let key = mint_cursor(&intents.asset);
|
||||
let mut backward_turn = false;
|
||||
loop {
|
||||
if chain.read().current_runtime().is_none() {
|
||||
tokio::time::sleep(RETRY).await;
|
||||
@@ -165,17 +166,23 @@ async fn mints(
|
||||
}
|
||||
};
|
||||
let (low, high) = cursor.unwrap_or((tip, tip.saturating_sub(1)));
|
||||
let (heights, descending): (Vec<u64>, bool) = if high < tip {
|
||||
((high + 1..=tip.min(high + BATCH)).collect(), false)
|
||||
} else if low > oldest {
|
||||
(
|
||||
(low.saturating_sub(BATCH).max(oldest)..low).rev().collect(),
|
||||
true,
|
||||
)
|
||||
} else {
|
||||
tokio::time::sleep(TIP_WAIT).await;
|
||||
continue;
|
||||
};
|
||||
// Every other pass goes back while there is history left: forward passes
|
||||
// take longer than NEAR's 0.6 s blocks, so a scan that waited to be
|
||||
// level with the tip before going back never went back at all — the
|
||||
// bridge's mint backfill sat with 118,898 blocks unread (2026-10-07).
|
||||
backward_turn = !backward_turn;
|
||||
let (heights, descending): (Vec<u64>, bool) =
|
||||
if high < tip && !(backward_turn && low > oldest) {
|
||||
((high + 1..=tip.min(high + BATCH)).collect(), false)
|
||||
} else if low > oldest {
|
||||
(
|
||||
(low.saturating_sub(BATCH).max(oldest)..low).rev().collect(),
|
||||
true,
|
||||
)
|
||||
} else {
|
||||
tokio::time::sleep(TIP_WAIT).await;
|
||||
continue;
|
||||
};
|
||||
let Ok(layout) = near.shard_layout(heights[0]).await else {
|
||||
tokio::time::sleep(RETRY).await;
|
||||
continue;
|
||||
|
||||
@@ -133,6 +133,7 @@ pub fn spawn(chain: Arc<ChainRuntime>, store: Store) {
|
||||
/// Walk NEAR blocks, recording trades.
|
||||
async fn scan(chain: Arc<ChainRuntime>, store: Store, near: NearClient, config: IntentsConfig) {
|
||||
let id = chain.id();
|
||||
let mut backward_turn = false;
|
||||
loop {
|
||||
// The cursor references the chain row, which the chain's own poll
|
||||
// writes once its node has answered.
|
||||
@@ -161,15 +162,21 @@ async fn scan(chain: Arc<ChainRuntime>, store: Store, near: NearClient, config:
|
||||
// than what traded last week, and both arrive in the end.
|
||||
let (low, high) = scan.unwrap_or((tip, tip.saturating_sub(1)));
|
||||
|
||||
let (heights, descending): (Vec<u64>, bool) = if high < tip {
|
||||
((high + 1..=tip.min(high + BATCH)).collect(), false)
|
||||
} else if low > config.start_height {
|
||||
let floor = low.saturating_sub(BATCH).max(config.start_height);
|
||||
((floor..low).rev().collect(), true)
|
||||
} else {
|
||||
tokio::time::sleep(TIP_WAIT).await;
|
||||
continue;
|
||||
};
|
||||
// Every other pass goes back while there is history left: forward passes
|
||||
// take longer than NEAR's 0.6 s blocks, so a scan that waited to be
|
||||
// level with the tip before going back never went back at all — the
|
||||
// bridge's mint backfill sat with 118,898 blocks unread (2026-10-07).
|
||||
backward_turn = !backward_turn;
|
||||
let (heights, descending): (Vec<u64>, bool) =
|
||||
if high < tip && !(backward_turn && low > config.start_height) {
|
||||
((high + 1..=tip.min(high + BATCH)).collect(), false)
|
||||
} else if low > config.start_height {
|
||||
let floor = low.saturating_sub(BATCH).max(config.start_height);
|
||||
((floor..low).rev().collect(), true)
|
||||
} else {
|
||||
tokio::time::sleep(TIP_WAIT).await;
|
||||
continue;
|
||||
};
|
||||
|
||||
// Per batch, not once: resharding renumbers shards, and a layout read
|
||||
// at startup would follow the wrong one after it while every call
|
||||
|
||||
@@ -141,6 +141,7 @@ async fn scan(chain: Arc<ChainRuntime>, store: Store, near: NearClient, config:
|
||||
let token = config.token_contract().unwrap_or_default().to_owned();
|
||||
let holder = config.contract.clone();
|
||||
tracing::info!(chain = %id, %token, %holder, "following the asset into and out of NEAR Intents");
|
||||
let mut backward_turn = false;
|
||||
loop {
|
||||
if chain.read().current_runtime().is_none() {
|
||||
tokio::time::sleep(RETRY).await;
|
||||
@@ -166,7 +167,12 @@ async fn scan(chain: Arc<ChainRuntime>, store: Store, near: NearClient, config:
|
||||
// and the first block above it has no "before" to compare with.
|
||||
let floor = oldest.max(config.start_height) + 1;
|
||||
let (low, high) = cursor.unwrap_or((tip, tip.saturating_sub(1)));
|
||||
let (from, to, descending) = if high < tip {
|
||||
// Every other pass goes back while there is history left: forward passes
|
||||
// take longer than NEAR's 0.6 s blocks, so a scan that waited to be
|
||||
// level with the tip before going back never went back at all — the
|
||||
// bridge's mint backfill sat with 118,898 blocks unread (2026-10-07).
|
||||
backward_turn = !backward_turn;
|
||||
let (from, to, descending) = if high < tip && !(backward_turn && low > floor) {
|
||||
(high + 1, tip.min(high + BATCH), false)
|
||||
} else if low > floor {
|
||||
(low.saturating_sub(BATCH).max(floor), low - 1, true)
|
||||
|
||||
@@ -104,6 +104,7 @@ async fn scan(chain: Arc<ChainRuntime>, store: Store, near: NearClient, config:
|
||||
let key = cursor_key(&config.asset);
|
||||
let pools = crate::refdcl::contracts(&config);
|
||||
let asset_contract = config.token_contract().unwrap_or_default().to_owned();
|
||||
let mut backward_turn = false;
|
||||
loop {
|
||||
if chain.read().current_runtime().is_none() {
|
||||
tokio::time::sleep(RETRY).await;
|
||||
@@ -127,15 +128,21 @@ async fn scan(chain: Arc<ChainRuntime>, store: Store, near: NearClient, config:
|
||||
};
|
||||
let (low, high) = cursor.unwrap_or((tip, tip.saturating_sub(1)));
|
||||
let floor = oldest.max(config.start_height);
|
||||
let (heights, descending): (Vec<u64>, bool) = if high < tip {
|
||||
((high + 1..=tip.min(high + BATCH)).collect(), false)
|
||||
} else if low > floor {
|
||||
let from = low.saturating_sub(BATCH).max(floor);
|
||||
((from..low).rev().collect(), true)
|
||||
} else {
|
||||
tokio::time::sleep(TIP_WAIT).await;
|
||||
continue;
|
||||
};
|
||||
// Every other pass goes back while there is history left: forward passes
|
||||
// take longer than NEAR's 0.6 s blocks, so a scan that waited to be
|
||||
// level with the tip before going back never went back at all — the
|
||||
// bridge's mint backfill sat with 118,898 blocks unread (2026-10-07).
|
||||
backward_turn = !backward_turn;
|
||||
let (heights, descending): (Vec<u64>, bool) =
|
||||
if high < tip && !(backward_turn && low > floor) {
|
||||
((high + 1..=tip.min(high + BATCH)).collect(), false)
|
||||
} else if low > floor {
|
||||
let from = low.saturating_sub(BATCH).max(floor);
|
||||
((from..low).rev().collect(), true)
|
||||
} else {
|
||||
tokio::time::sleep(TIP_WAIT).await;
|
||||
continue;
|
||||
};
|
||||
|
||||
let mut layout = None;
|
||||
for &height in &heights {
|
||||
|
||||
Reference in New Issue
Block a user