Multi-copy upload: deposit from `prepare()` can be short by the time a later commit executes (`insufficient funds to cover lockup after function execution`)

オープン
#1,099 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
4/5
見積もり時間
3〜5日
初心者へのやさしさ
48/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
node.js, typescript

調査の方向性

Start by tracing storage.prepare() and the multi-context upload commit flow, including DEFAULT_BUFFER_EPOCHS and DEFAULT_RUNWAY_EPOCHS; inspect the transaction error handling for createDataSetAndAddPieces and addPieces. Reproduce with multiple contexts and verify that preparation covers lockup needs as epochs pass, or that a commit reports the decoded revert reason. The issue names no source or test files, so first locate the relevant code and tests.

索引モデルが issue の本文から書いたものです。

説明

Summary

With two contexts (primary store plus SP-to-SP pull to a secondary), storage.prepare() computed and deposited the funds for both copies. The secondary's addPieces was submitted first and succeeded. The primary's createDataSetAndAddPieces, submitted a second later, executed about 4–6 epochs after prepare() read the account state and reverted in Filecoin Pay with insufficient funds to cover lockup after function execution. The shortfall was about 0.00001 USDFC. The upload result was correctly complete: false with one copy, but the only error reported was Commit failed. We found the reason by replaying the reverted transaction with eth_call.

The default deposit buffer is 5 epochs (DEFAULT_BUFFER_EPOCHS). In a multi-copy flow, store, pull and the commits take minutes, and the commits are executed by different providers at different epochs. 5 epochs leaves almost no margin.

Version
  • @filoz/synapse-sdk 2.0.2, @filoz/synapse-core 0.10.3, viem 2.57.16, Node 24
  • Calibration (chain 314159)
  • DEFAULT_BUFFER_EPOCHS = 5n and DEFAULT_RUNWAY_EPOCHS = 0n are unchanged on the default branch as of 2026-11-10.
Steps to reproduce (what we ran)

The client account already had a Filecoin Pay balance and active rails from earlier uploads. Provider 9 got a new data set. Provider 61 reused an existing data set (51317).

Simplified (metadata and callbacks omitted):

const contexts = await synapse.storage.createContexts({ providerIds: [9n, 61n], copies: 2 })
const prep = await synapse.storage.prepare({ context: contexts, pieceSizes: [BigInt(data.byteLength)] }) // 2 MiB
await prep.transaction.execute() // deposit 0.620083151414808445 USDFC (lockup total 0.620009536881776 USDFC)
const up = await synapse.storage.upload(data, { contexts })

Timeline (2026-11-07, UTC):

Time Epoch Event
08:55:59 ≈ 4223845–4223846 prepare() computes costs: depositNeeded 0.620083151414808445 USDFC
08:57:10 4223847 deposit transaction included
08:57:19 SP-to-SP pull to provider 61 complete
08:57:20 commit at 61 submitted (addPieces to the existing data set). It succeeded: data set 51317 holds the piece
08:57:21 executed in 4223850 commit at 9 submitted (createDataSetAndAddPieces): 0x48a0c06702359c43ec8b06f51cebd0d89623e9ba5387e17ce5aeb66311995a2c, status 0
09:02:21 upload() returns complete: false, copies: [61], failedAttempts: [{ providerId: 9, role: 'primary', error: 'Commit failed' }]

The reverted transaction: https://calibration.filfox.info/en/message/0x48a0c06702359c43ec8b06f51cebd0d89623e9ba5387e17ce5aeb66311995a2c (exit code 33).

Replaying the reverted transaction with eth_call at its block returned the Filecoin Pay revert insufficient funds to cover lockup after function execution. The shortfall was about 0.00001 USDFC.

We did not retry, to avoid adding a duplicate piece to the existing data set.

Expected

Either:

  • prepare() deposits enough for all contexts to commit, including the epochs that pass during store, pull and commit, and including the order in which providers execute their commits; or
  • the SDK checks the account's available funds against the lockup each commit will need just before it signs that commit, and tops up or fails early with a clear message.

And in both cases, a failed commit reports the revert reason, not only Commit failed.

Actual

The second commit to execute reverted, short by about 0.00001 USDFC. The client got a partial placement (1 of 2 copies) with the error Commit failed.

Suggestions
  1. Use a larger default bufferEpochs when prepare() gets more than one context, or scale it with the expected store/pull/commit time. Or document clearly that multi-copy callers should pass bufferEpochs / extraRunwayEpochs.
  2. Re-check funds before signing each commit (createDataSetAndAddPieces / addPieces extra data) and include the shortfall in the error.
  3. Include the decoded revert reason in failedAttempts[].error when a commit transaction reverts.
Our workaround

For multi-copy uploads we now pass extraRunwayEpochs: 240n to prepare(), capped at 0.1 USDFC with a hard ceiling of 1 USDFC. With that, a new placement on providers 9 and 61 (data sets 51840 and 51841, 2026-11-08) committed on both. The margin used was about 0.0023 USDFC. Both data sets have since had every ended proving period proven.


Reported by BlockX Labs. This report was written by our AI operations agent from our own run logs and on-chain data, and a human on the team approved posting it. The read-only scripts we use to check proof status and retrieval are at https://github.com/blockxlabs-ai/pdp-evidence-scripts.

主要言語
TypeScript
スター
28
フォーク
35
平均マージ
2日 4時間
マージ済み PR(30日)
44

環境構築

Codespaces で開く

このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

FilOzone/synapse-sdk のほかの issue

FilOzone/synapse-sdk の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。