Sui.

Пост

Поделитесь своими знаниями.

Награда+15

Xavier.eth.
Jun 27, 2025
Экспертные Вопросы и Ответы

Сбой транзакции Sui: объекты, зарезервированные для другой транзакции

JsonRpcErrorПри попытке выполнить транзакции на Sui возникает постоянная ошибка. Ошибка означает, что объекты зарезервированы для другой транзакции, несмотря на то, что я реализовал последовательную обработку транзакций с задержками.

JsonRpcError: Failed to sign transaction by a quorum of validators because one or more of its objects is reserved for another transaction. Other transactions locking these objects:
- AV7coSQHWg5vN3S47xada6UiZGW54xxUNhRv1QUPqWK (stake 33.83)
    - 0x1c20f15cbe780ee7586a2df90c1ab70861ca77a15970bea8702a8cf97bd3eed9
    - 0x1c20f15cbe780ee7586a2df90c1ab70861ca77a15970bea8702a8cf97bd3eed9
    - 0x1c20f15cbe780ee7586a2df90c1ab70861ca77a15970bea8702a8cf97bd3eed9

Я попробовал:

  • Последовательное выполнение транзакции (ожидание завершения предыдущей транзакции)
  • Добавлены 3-секундные задержки между транзакциями

И все еще постоянно возникает одна и та же ошибка.

Использование Sui RPC для отправки транзакций. Один и тот же идентификатор объекта несколько раз появляется в списке блокировок. Ошибка возникает даже при тщательном определении последовательности транзакций.

  1. Почему объекты «зарезервированы» для других транзакций?
  2. Как правильно проверить, доступен ли объект, прежде чем использовать его в транзакции?
  3. Существуют ли передовые методы работы с замками объектов в Sui?
  4. Может ли это быть связано со сроками завершения транзакции?

Кто-нибудь сталкивался с этой проблемой раньше? Мы будем очень признательны за любую информацию о правильном управлении объектами в транзакциях Sui!

  • Sui
  • Transaction Processing
  • Move
4
10
Поделиться
Комментарии
.

Ответы

10
harry phan.
Jun 30 2025, 15:00

Эта ошибка возникает, если вы пытаетесь выполнить две транзакции одновременно (например, начать одну до завершения предыдущей). Если вы повторите попытку запуска транзакции публикации, не выполняя другую транзакцию ранее или одновременно, она должна завершиться успешно. Кроме того, вам, возможно, придется добыть больше газа из крана (или подождать целый день, пока эпоха не закончится, а объекты разблокируются)

Когда вы проводите транзакцию с объектами, принадлежащими вашему адресу (например, газовые объекты), валидаторы резервируют последнюю версию объекта для использования в подписываемой транзакции. Если вы попытаетесь запустить две транзакции одновременно, и они относятся к одному и тому же объекту, они будут конкурировать друг с другом за подписи валидаторов. В счастливом случае одна из транзакций выигрывает и выполняется, а другая транзакция не получает достаточного количества подписей. В печальном случае обе транзакции могут не набрать достаточного количества подписей (если обе транзакции набрали более трети подписей валидатора, то ни одна из них не сможет набрать более двух третей, что является пороговым значением). Это называется двусмысленностью, и с этого момента объекты, использовавшиеся в обеих транзакциях, нельзя использовать для других транзакций.

В конце эпохи (они длятся примерно один день — вы можете следить за переходом к следующей эпохе на сайте https://suiexplorer.com) все блокировки снимаются, поэтому вы можете снова использовать объекты, но если вы не меняли эпоху с момента последней попытки, вам нужно будет купить больше газа.

12
Комментарии
.
0xduckmove.
Jun 30 2025, 07:04

Эй, вы пытаетесь выполнить транзакцию слишком быстро, и объекты заблокированы.

Попробуйте отправлять по одной транзакции с одними и теми же объектами за раз. Если вы отправите две транзакции, некоторые валидаторы могут принять первую транзакцию, другие могут принять вторую, а ваши объекты будут заблокированы, так как для каждой транзакции требуется 66,7% валидаторов, а вы, возможно, получаете только 50%.

=> просто дождитесь перезагрузки эпохи, скоро

Узнайте больше: https://forums.sui.io/t/beginner-tutorial-error-when-deploying-simple-sui-package/44842

6
Комментарии
.
Owen.
Owen4662
Jun 30 2025, 11:03

Sui используетоптимистичное управление параллелизмом, то есть объекты блокируются при использовании в транзакции до завершения транзакции или истечения срока ее действия.

Даже если вы подождете 3 секунды между транзакциями, если предыдущая транзакция еще не была завершена, объект останется заблокированным. Это означает, что транзакция все еще находится на рассмотрении и имеет эксклюзивный доступ к объекту.


Как проверить, доступен ли объект

Используйте метод Sui RPC:

sui_getObject

Проверьте ответ на вопрос "status": "Locked"или"owner": "locked".

Пример запроса:

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "sui_getObject",
  "params": ["0x...object_id..."]
}

Если заблокировано, подождите еще раз и повторите попытку позже.

5
Комментарии
.
MiniBob.
Jun 30 2025, 11:50

Ошибка означает, что объекты, используемые в транзакции, по-прежнему заблокированы предыдущими транзакциями, которые еще не завершены. Даже несмотря на задержки, объекты остаются зарезервированными до завершения транзакций в блокчейне.

Для исправления:

  1. Всегда проверяйте, что предыдущие транзакции с объектами полностью завершены, прежде чем использовать их снова.
  2. Проверьте состояние объектов с помощью Sui RPC, чтобы убедиться, что они разблокированы.
  3. Избегайте параллельной или быстрой отправки транзакций по одним и тем же объектам.
  4. Вместо фиксированных задержек применяйте повторные попытки с проверкой сроков выполнения заказа и выполнения заказа.

Такая блокировка предотвращает появление конфликтующих обновлений и является обычным явлением в объектной модели Sui. JsonRpcErrorПравильная последовательность действий и подтверждение окончательности — ключ к тому, чтобы избежать ошибок.

4
Комментарии
.
BigDev.
Aug 15 2025, 16:24

Эта ошибка означает, что используемые вами объекты по-прежнему заблокированы предыдущими транзакциями, которые еще не завершились. Даже в случае задержек компания Sui сохраняет их в резерве до тех пор, пока цепочка не подтвердит завершение сделки.

Чтобы исправить эту проблему, убедитесь, что все предыдущие транзакции с использованием этих объектов полностью завершены, прежде чем использовать их повторно. Вы можете проверить их статус через Sui RPC, чтобы узнать, разблокированы ли они. Избегайте отправки нескольких или быстрых транзакций с использованием одних и тех же объектов. Вместо того чтобы полагаться на фиксированные задержки, используйте повторные попытки с возвратом и подтвердите окончательность перед повторной попыткой.

Эта блокировка является частью того, как Sui обеспечивает безопасные обновления, поэтому правильная последовательность и проверка окончательности — это способ избежать ошибки JSONRPCError

2
Комментарии
.
0xF1RTYB00B5.
Sep 18 2025, 16:25

That’s a great debugging question — I’ve run into this exact issue before when building staking flows on Sui. Let me answer in detail, step-by-step, from my perspective using Sui daily.


🔍 Why objects get “reserved” in Sui

In Sui, every transaction consumes specific object versions. Once you submit a transaction that references an object, the network puts a lock on that object version until the transaction is finalized (committed or fails).

So when you see:

JsonRpcError: Failed to sign transaction ... one or more of its objects is reserved

it means:

  • The object version you’re trying to use is still “in flight” (reserved by another PTB),
  • Or you’re re-using an outdated version without refreshing from the fullnode,
  • Or the validator quorum hasn’t yet reached finality for the first transaction.

That’s why the same objectId shows multiple times in the lock list — you’re trying to consume the same locked version repeatedly.


✅ How I check object availability before using

I always follow these steps:

  1. After each transaction, re-fetch fresh object refs before building the next transaction block.

    const fresh = await provider.getObject({
      id: "0x1c20f15cbe780ee...",
      options: { showOwner: true, showPreviousTransaction: true, showContent: true },
    });
    const version = fresh.data.version; // must use this version in the next PTB
    
  2. Wait for local execution / finality when submitting. Always request WaitForLocalExecution in your signAndExecuteTransactionBlock. This ensures the object is unlocked before you try to use it again.

    const res = await signer.signAndExecuteTransactionBlock({
      transactionBlock: tx,
      requestType: "WaitForLocalExecution",
    });
    
  3. Implement a retry with exponential backoff when conflicts occur. Even with sequencing, there are cases where the fullnode lags. I use a submitWithRetry wrapper (like the one I showed earlier) that catches Object version mismatch and retries after re-fetching the object.


⚡ Best practices for handling object locks

  • Never reuse old object references. Always fetch the latest state from the RPC before constructing each PTB.
  • Design with parallelism in mind. If multiple independent flows need the same object, shard state across multiple owned objects (avoid a single global shared object).
  • Batch operations when possible. Use a single TransactionBlock with multiple Move calls instead of sending sequential transactions that lock the same object repeatedly.
  • Add backoff + retries. I usually back off 100ms, 200ms, 400ms, 800ms … up to ~3s before giving up.
  • Use checkpoints/finality awareness. Remember: an object isn’t truly free until the checkpoint is committed.

⏱️ Relation to finality timing

Yes, this is directly related. Even after a transaction appears “executed”, the object may remain reserved until:

  • The local fullnode confirms execution,
  • The consensus checkpoint includes it,
  • The version updates propagate across validators.

That’s why adding a blind 3-second delay isn’t reliable — network conditions and validator lag can extend this. The right way is fetch-after-execution instead of sleeping.


🛠️ Example: Safe sequential staking

Here’s how I do it in code (simplified):

async function safeStake(signer, validatorAddr, stakeAmountMist, stakeObjectId) {
  let attempt = 0;
  while (attempt < 5) {
    try {
      // 1. Fetch latest object version
      const obj = await provider.getObject({ id: stakeObjectId, options: { showOwner: true } });
      const version = obj.data.version;

      // 2. Build PTB with fresh version
      const tx = new TransactionBlock();
      tx.moveCall({
        target: "0x2::staking::request_add_stake",
        arguments: [tx.pure(validatorAddr), tx.pure(stakeAmountMist.toString())],
        typeArguments: [],
      });

      // 3. Execute with finality wait
      const res = await signer.signAndExecuteTransactionBlock({
        transactionBlock: tx,
        requestType: "WaitForLocalExecution",
      });

      console.log("✅ success:", res.digest);
      return res;
    } catch (e) {
      if (e.message.includes("reserved") || e.message.includes("Object version mismatch")) {
        attempt++;
        const backoff = 200 * 2 ** attempt;
        console.warn(`conflict, retrying in ${backoff}ms`);
        await new Promise(r => setTimeout(r, backoff));
        continue;
      }
      throw e;
    }
  }
  throw new Error("failed after retries");
}

This ensures:

  • I always use the latest object version,
  • I wait for finality,
  • I retry on transient lock errors.

🧩 TL;DR

  • Cause: Object locks happen because an object version is still reserved by an in-flight transaction.
  • Fix: Always re-fetch latest object versions, wait for local execution, and retry on conflicts.
  • Best practice: Shard state, batch operations, and use retries/backoff rather than fixed sleeps.
  • Yes, finality timing matters. Blind delays won’t solve it — confirmation checks + re-fetching will.
0
Комментарии
.

Знаете ответ?

Пожалуйста, войдите в систему и поделитесь им.