Пост
Поделитесь своими знаниями.
Паттерны проектирования и управление параллелизмом для общих объектов в Sui Move
При работе с общими объектами в Sui Move я пытаюсь найти правильный архитектурный паттерн, особенно когда с ними приходится работать одновременно нескольким пользователям (например, на игровой арене, в системе отслеживания голосов DAO или при аренде хранилища).
Я читал, что общие объекты могут создавать проблемы с синхронизацией, но мне все еще неясно:
- Когда именно мне следует использовать
shared
объект или когдаowned
? - Как Sui обрабатывает одновременные попытки транзакций с одним и тем же общим объектом — нужно ли вручную ставить объекты в очередь или блокировать их?
ConflictTransaction
* Какова наилучшая практика разработки модулей, поддерживающих высокий уровень параллелизма, но исключающих частые ошибки? - Должен ли я делать что-то особенное (например, разбивать изменяемые поля на подобъекты), чтобы уменьшить конкуренцию?
- Sui
- Architecture
- NFT Ecosystem
- Move
Ответы
13При создании приложения dApp на Sui, в котором нескольким пользователям приходится взаимодействовать в одном и том же состоянии (например, на игровой арене, в протоколе кредитования или в DAO), вам следует использоватьобщие объектывместо принадлежащих вам объектов. Общие объекты общедоступны и могут быть изменены, а это значит, что каждый может вызывать функции ввода в них, пока они находятся в глобальном графе объектов. Напротив, принадлежащие пользователю объекты являются конфиденциальными и идеально подходят для хранения личных активов, таких как кошельки или инвентарь. Поэтому следует использовать общий объект, когда обновления состояния должны быть видны и доступны нескольким пользователям одновременно.
Sui обрабатывает параллельные транзакции с общими объектами с помощью механизмапроверки причинного порядка, который требует явного указания последней известной версии общего объекта. ConflictTransaction
Если два пользователя одновременно попытаются изменить один и тот же общий объект с помощью устаревших версий, один из них добьется успеха, а остальные — с ошибкой. Sui изначально не ставит общие объекты в очередь и не блокирует их, поэтому необходимо спроектировать модули Move таким образом, чтобы свести к минимуму дублирование операций записи. Один из лучших способов уменьшить конфликты —проектировать с учетом параллелизма. Например, вместо сохранения всех изменяемых состояний в общем корневом объекте можноразделить поля с высоким уровнем конкуренции на отдельные дочерние объекты. Затем каждый из этих дочерних элементов можно будет написать отдельно, что снизит вероятность конфликтов транзакций.
Рекомендуется сохранить основной общий объект в виде каталога и перенести детальную, часто обновляемую информацию (например, результаты игроков, голоса или остатки по кредитам) в динамические поля или небольшие подобъекты. Таким образом, пользователи обновляют только нужную им часть, а не весь общий объект. Также разумно разделять компоненты, требующие большого количества чтения и записи. Кроме того, следует создавать четкие и детерминированные потоки транзакций, в которых всегда используются самые свежие версии общих объектов и логика повторных попыток, позволяющая клиентам обрабатывать неудачные транзакции.
Подробнее о проектировании общих объектов и устранении конфликтов можно узнать в документации Sui здесь: https://docs.sui.io/concepts/objects#shared-objects.
Если вы управляете чем-то вроде трекера голосов, вот пример упрощенного блока транзакций, позволяющего уменьшить количество конфликтов:
const tx = new TransactionBlock();
tx.moveCall({
target: `$ {PackageID} ::vote_tracker: :cast_vote`,
аргументы: [
tx.SharedObject (VoteTrackerId),//ссылка на общий объект
tx.pure (VoteRid),//собственный объект или открытый ключ
tx.pure (ProposalID),//чистые данные
tx.pure (выбор голосов)
]
});
В Sui Moveобщие объекты(отмеченные значкомkey + store
) необходимы для многопользовательского взаимодействия, но требуют тщательного параллельного проектирования. Используйте их, когда состояние должно быть глобально изменчивым (например, игры, DAO), а объекты, принадлежащие или неизменяемые, подходят для однопользовательских сценариев. Sui автоматически сериализует транзакции по каждому общему объекту, но частая запись может привести к ConflictTransaction
ошибкам. Для устранения этой проблемы используйтеразделение горячих полейна отдельные дочерние объекты (например, по одному на пользователя) или пакетное обновление. Для повышения пропускной способности используйтесхемы поиска событий: сохраняйте действия в виде неизменных событий и периодически агрегируйте состояние. transfer::share_object
Всегда сводите к минимуму количество изменяемых общих полей и отдавайте предпочтение атомарным заменам, а не прямым мутациям.
В Sui Move эффективное управление общими объектами и параллелизмом требует тщательного проектирования, позволяющего избежать условий гонки и высокой конкуренции. Вот краткое изложение лучших практик и архитектурных шаблонов:
1.Когда использовать объекты, находящиеся в совместном пользовании, и объекты, находящиеся в собственности:
*Общие объекты: используйте, когда нескольким пользователям необходимо одновременно взаимодействовать с одним и тем же объектом (например, общее состояние игры, система отслеживания голосов DAO). *Собственные объекты: используйте объект, предназначенный только для одного пользователя или учетной записи, что позволяет избежать общего состояния и уменьшить количество проблем с параллелизмом.
2.Параллельная обработка транзакций в Sui:
- Sui автоматически обрабатывает параллелизм, используяTransactionLock, чтобы предотвратить одновременное изменение одного и того же объекта.
- Вамненужно вручную ставить в очередь или блокировать общие объекты, так как Sui применяет блокировку на уровне объектов. Однаковы можете получить ошибки ConflictTransaction, если несколько транзакций конфликтуют на одном объекте.
3.Лучшие практики обеспечения высокого уровня параллелизма:
*Минимизируйте противоречие: разделите изменяемые поля на отдельные подобъекты, чтобы обеспечить параллельное обновление различных частей объекта. *Избегайте «горячих точек»: распределяйте часто изменяемое состояние по нескольким объектам (например, вместо единого общего реестра разделите его на несколько сегментов или счетов). *Управление версиями: используйте версионные объекты или создавайте новые объекты для отслеживания обновлений вместо многократного изменения одного и того же объекта.
4.Управление конфликтом:
- Рассмотрите возможностьразделения изменяемых полей на более мелкие объекты, чтобы уменьшить конкуренцию. Это позволяет обновлять разные части объекта одновременно, что снижает вероятность конфликтов.
- Используйтеатомарные транзакциидля объединения связанных действий в одно целое, обеспечивая согласованность между связанными объектами.
Пример:
Если у вас естьтрекер голосовза DAO:
- Вместо того чтобы хранить все голоса в одном общем объекте, разделите их на несколько объектов (например, по одному на каждое предложение), что позволит параллельно обновлять каждое предложение и при этом снизить уровень конкуренции.
Заключение:
Чтобы обеспечить высокий уровень параллелизма, минимизируйте конкуренцию, распределяя состояние, используя подобъекты и используя автоматическую обработку транзакций Sui. Убедитесь, что вы понимаете свои шаблоны доступа и структурируете объекты таким образом, чтобы свести к минимуму количество конфликтных точек.
Понимание шаблонов проектирования и управления параллелизмом для общих объектов в Sui Move
При работе с общими объектамивSui Moveуправление параллелизмом становится критически важным, поскольку нескольким пользователям может потребоваться одновременно работать с одним и тем же объектом. Это особенно актуально для таких вариантов использования, какигровые арены**,трекеры голосования DAOисдача в аренду хранилища, где ожидается высокий уровень параллелизма. В сети Sui есть некоторые функции, помогающие управлять параллелизмом, но все же ее необходимо тщательно продумать, чтобы избежать распространенных ошибок, таких как ошибкиConflictTransaction.
1.Когда использовать общие объекты или объекты, принадлежащие собственности
*Предметы, находящиеся в собственности:
-
Объект является собственностью**, если им управляет один адрес, который может передавать или изменять объект. *Используйте принадлежащие объекты, если вы ожидаете, что один объект будет контролировать объект и взаимодействовать с ним. Например, если у вас есть кошелек с монетами, каждый кошелек владеет своими монетами. *Общие объекты:
-
К общим объектам можно обращаться и изменять их одновременно по нескольким адресам. Sui позволяет определять объекты как объектысовместно используемые, делая их изменяемыми и предоставляя доступ нескольким сторонам. *Используйте общие объектыдля сценариев, в которых несколько пользователей или адресов должны взаимодействовать с одним и тем же объектом, например:
*Трекеры голосования DAO: несколько пользователей могут голосовать за один и тот же объект. *Хранилища для кредитования: несколько пользователей могут брать взаймы и займы в одном хранилище. *Игровые арены: несколько пользователей одновременно взаимодействуют с игровым состоянием.
Ключевое соображение: общие объекты следует использовать осторожно, так как они могут привести к возникновению разногласий**— ситуаций, когда несколько транзакций пытаются получить доступ к одному и тому же объекту и изменить его одновременно.
2.Параллелизм и попытки транзакций с общими объектами
Sui обеспечивает правильную обработку параллельныхтранзакцийна одном и том жеобщем объекте, применяятранзакционную изоляцию. Если несколько транзакций попытаются изменить один и тот же общий объект одновременно, одна из них завершится неудачей из-за разногласия**.
Когда транзакция попытается изменить общий объект, который уже был изменен другой транзакцией, Sui вернет ошибкуConflictTransaction. ОднакоSui выполняет большую часть управления параллелизмом внутренним, и вамне нужно вручную ставить объекты в очередь или блокировать. Вместо этого вам необходимо разработать контракт таким образом, чтобы свести к минимуму разногласия и избежать ситуаций, когда две транзакции часто конфликтуют.
3.Лучшие практики для обеспечения высокого уровня параллелизма и снижения количества конфликтных транзакций
Чтобыпроектировать модули, способные работать с высоким уровнем параллелизма и избегать частых ошибокConflictTransaction, следуйте этим рекомендациям:
a.Минимизируйте количество соперников:
*Ограничьте изменяемый доступ: как можно меньше изменяемых полей в общих объектах. Каждое изменяемое поле создает потенциальную спорную точку. *Используйте принадлежащие объекты для независимых данных: вместо того, чтобы предоставлять доступ ко всем данным, храните независимые данные в принадлежащих им объектах. Например, если у вас есть данные, специфичные для пользователя (например, баланс), храните их в принадлежащем, а не в общем объекте.
b.Используйте шаблон «Разделение состояний»:
-
Разделите общий объект нанесколько подобъектов, чтобы уменьшить противоречие. Например, вместо одного общего объекта, отслеживающего состояние игры в целом, вы можете разделить его на несколько подобъектов:
-
По одному на состояние каждогоигрока.
-
Один занастройки игры.
-
Один заданные таблицы лидеров.
-
Таким образом, транзакции, относящиеся к различным частям системы, могут происходить одновременно, не блокируя друг друга.
c.Пакетные операции:
- При работе с общими объектами пакетируйте обновления, чтобы сократить количество транзакций, необходимых для взаимодействия с объектом. Это поможет избежать частых конфликтов. *Используйте коллекциив виде векторов или наборов для управления несколькими обновлениями за одну транзакцию.
d.Используйте атомные операции:
- По возможности разрабатывайте свои модули таким образом, чтобы использовать атомарные операции там, где это возможно. Например, вместо того чтобы проводить отдельные транзакции для проверки условия и последующего обновления поля, объедините проверки и обновления в одну атомарную операцию.
e.Логика повторов:
- Хотя Sui обрабатывает повторные попытки самостоятельно, вы можете реализовать логику повторов на уровне приложения для обработки случайных конфликтных ошибок. Например, в случае
ConflictTransaction
ошибки можно просто повторить транзакцию или поставить ее в очередь для последующего выполнения.
4.Уменьшение конкуренции за счет разделения изменяемых полей на подобъекты
Это настоятельно рекомендуемая практика. При работе с общими объектамичем больше полей в общем объектеявляются изменяемыми, тем выше вероятность того, что две транзакции попытаются изменить одно и то же поле одновременно.
*Пример 1: если у вас есть общий объект, представляющий собойлендинговое хранилище, разделите его на подобъекты:
- Один длядепозитов: отслеживайте индивидуальные депозиты отдельно.
- Один длякредитов: отслеживайте отдельные займы отдельно.
- Один вариант длясостояния хранилища: отслеживайте общую информацию о состоянии (например, общую стоимость, процентную ставку).
Таким образом, транзакция, изменяющая один подобъект (например, подобъекткредит), не будет конфликтовать с транзакцией, изменяющей другой объект (например, подобъектдепозит).
*Пример 2: наигровой арене:
- Разделите состояние игры на подобъекты для каждого игрока, состояние игры и статистику сражений. Это снижает риск конфликтов при взаимодействии разных игроков со своими игровыми состояниями.
Разбивая изменяемые поля наподобъекты, вы уменьшаете вероятность того, что несколько пользователей попытаются изменить один и тот же объект одновременно.
5.Другие методы управления параллелизмом в Sui
*Блокировка (явные блокировки): хотя Sui не требует ручной обработки блокировок, в некоторых случаях вы можете захотеть ввестиявные блокировкис помощью объектовблокировки(отдельных объектов, обеспечивающих одновременный доступ к определенному ресурсу только одной транзакции).
*Временная изоляция: если ваши объекты меняются лишь изредка, попробуйте ввестивременную изоляцию. Например, если вы управляете хранилищем или системой голосования, задайтепериоды голосованияилиокна транзакций, чтобы ограничить взаимодействие в определенное время.
6.Пример кода для управления параллелизмом с подобъектами
Вот пример, иллюстрирующий, как уменьшить конкуренцию, разделивкредитное хранилищена более мелкие подобъекты:
module LendingVault {
struct Deposit has store {
amount: u64,
depositor: address,
}
struct Loan has store {
amount: u64,
borrower: address,
}
struct VaultState has store {
total_value: u64,
interest_rate: u64,
}
struct LendingVault has store {
deposits: vector<Deposit>,
loans: vector<Loan>,
vault_state: VaultState,
}
// Function to add a deposit
public fun add_deposit(vault: &mut LendingVault, depositor: address, amount: u64) {
let deposit = Deposit { amount, depositor };
Vector::push_back(&mut vault.deposits, deposit);
vault.vault_state.total_value = vault.vault_state.total_value + amount;
}
// Function to add a loan
public fun add_loan(vault: &mut LendingVault, borrower: address, amount: u64) {
let loan = Loan { amount, borrower };
Vector::push_back(&mut vault.loans, loan);
vault.vault_state.total_value = vault.vault_state.total_value - amount;
}
}
Резюме
*Используйте общие объекты, когда нескольким пользователям необходимо одновременно работать с одним и тем же объектом (например, голоса в DAO, состояние игры, предоставление хранилищ). *Минимизируйте конфликту, разделив большие общие объекты на более мелкие подобъекты и уменьшив количество изменяемых полей. *Избегайте частых ошибок ConflictTransaction, следуя передовым практикам, таким как разделение состояний, пакетные операции и использование атомарных операций.
- Для корректного разрешения конфликтов можно использовать логику повторовиоптимистичное управление параллелизмом**. *модель транзакций Suiиразрешение конфликтовнадежны, нодизайнсовместно используемых объектов играет ключевую роль в обеспечении эффективного параллельного доступа.
Следуя этим принципам проектирования, вы сможете обеспечить высокий уровень параллелизма в своих модулях на основе Move, избегая при этом типичных ловушек, таких как конфликтыиошибки транзакций**.
Используйтеобщие объектыдля доступа к нескольким файлам записи (например, к играм, DAO). Ключевые паттерны:
1.В собственности или в общении
- В собственности: один писатель (быстрее).
- Совместное использование: одновременная запись (более высокий уровень газа).
2.Параллельная обработка
- Автоматическая настройка последовательностей общих объектов TxS (без ручных блокировок).
- Разбивайте горячие данные на подобъекты (например, по одному на игрока), чтобы уменьшить количество конфликтов.
3.Смягчение конфликтов
Table<ID, PlayerData>
- Изолируйте поля с высокой посещаемостью (например,).
- Используйте PTB для атомных операций с несколькими объектами.
Следите за:
-ConflictTransaction
: Разделение данных или пакетное обновление.
- Резкие скачки газа на общих объектах.
- (Среда выполнения Sui обрабатывает конфликты, оптимизируя их с помощью сегментирования данных. ) *
Используйтеshared objects(transfer::share_object
), когда несколько пользователей должны изменить один и тот же объект (например, хранилище, DAO, состояние игры). В противном случае используйте символ «принадлежит»**.
TransactionLockConflict
Sui обрабатывает параллелизм в соответствии с принципомNarwhal и Tusk: конфликтующие транзакции в общем объекте сериализуются — за раунд выполняется только одна транзакция, другие — неудачная. Ручная блокировка не требуется, новы должны создать дизайн для повторных файлов.
Передовые практики:
- Минимизируйте изменяемое состояние общих объектов; разделите точки доступа на отдельные подобъекты (например, общие хранилища для каждого пользователя).
VecMap
- ИспользуйтеTable
или для масштабируемых сопоставлений. - Избегайте длительных вычислений в общих функциях.
- Генерируйте события вместо сохранения эфемерного состояния.
- В системах с высоким уровнем конкуренции используйте схемыпакетированиеиликоммит-раскрытие, чтобы уменьшить количество конфликтов.
Общие объекты доступны по всему миру, но вызывают больше проблем и противоречий. Оптимизируйте их, чтобы использовать в клиентском коде логику повтора и повтора.
Дляобщих объектовв Sui Move используйте следующие шаблоны для управления параллелизмом:
####1. Совместное или находящееся в собственности?
-Общий объект (key + store
):
- Используйте дляглобального состояния(например, игр, DAO).
- Разрешаетпараллельную запись(в отличие от сериализованных TX EVM).
struct GameArena has key, store { id: UID, players: vector<address> }
-Собственный объект:
- Используйте дляспецифичных для пользователейданных (например, NFT, кошельков).
struct PlayerInventory has key { id: UID, items: vector<Item> }
####2. Параллельная обработка -Без ручной блокировки: Suiразрешает конфликты автоматически(в отличие от EVM). -Разделение соперников: разбивайте общие объекты на более мелкие подобъекты**(например, на игрока или на осколок).
struct PlayerScore has key, store { id: UID, points: u64 } // Less contention
####3. Уменьшите количество ConflictTransaction
ошибок
-Изолируйте запись: обновитеразные поляв отдельных TX.
&mut
-Используйте с умом: избегайте массовых мутаций.
public entry fun update_score(
arena: &mut GameArena,
player: address,
points: u64
) { /* ... */ } // Only touches 1 player’s data
####4. Лучшие практики -Пакетные обновления: группируйте неконфликтные операции (например, голосования в DAO). -Управляемые событиями: по возможности генерируйте события, а не изменяйте состояние.
struct VoteEvent has copy, drop { voter: address, choice: u8 }
Используйте общие объекты для доступа к нескольким записям (например, игры, DAO). Ключевые паттерны:
В собственности или в совместном доступе
В собственности: один автор (быстрее). Совместно: одновременная запись (более высокий уровень газа). Обработка параллелизма
Автоматическое выполнение последовательностей общих объектов TxS (без ручных блокировок). Разделите горячие данные на подобъекты (например, по одному на игрока), чтобы уменьшить количество конфликтов. Устранение конфликтов
Изолируйте поля с высокой посещаемостью (например, таблицу<ID, PlayerData>). Используйте PTB для атомарных операций с несколькими объектами. Обратите внимание на:
ConflictTransaction: разделение данных или пакетное обновление. Пики газа на общих объектах. (Среда выполнения Sui обрабатывает конфликты, оптимизируя их с помощью сегментирования данных.)
In Sui Move, shared objects (marked with key + store) are essential for multi-user interaction but require careful concurrency design. Use them when state must be globally mutable (e.g., games, DAOs), while owned/immutable objects suit single-user scenarios. Sui serializes transactions per shared object automatically, but frequent writes may trigger ConflictTransaction errors—mitigate this by splitting hot fields into separate child objects (e.g., one per user) or batching updates. For high throughput, adopt event-sourcing patterns: store actions as immutable events and aggregate state periodically. Always minimize mutable shared fields and prefer atomic swaps via transfer::share_object over direct mutations
Объекты, находящиеся в совместном пользовании, и объекты, находящиеся в собственности: когда использовать каждый
Используйте общие объекты, когда:
- Несколько пользователей должны изменить одно и то же состояние
- Объект представляет собой публичный ресурс (например, игровую арену или DAO)
- Вам нужны шаблоны доступа без разрешений
Используйте принадлежащие вам объекты, когда:
- Объектом должен управлять только один адрес
- Вы хотите в полной мере использовать параллельное исполнение Sui
- Объекты представляют собой активы, специфичные для пользователя
Стратегии управления параллелизмом
1. Шаблон подобъекта (снижение конкуренции)
Разделите часто обновляемые поля на отдельные объекты:
struct GameArena has key {
id: UID,
// Immutable or rarely changed fields
config: ArenaConfig,
// Split mutable state
player_state: Table<address, PlayerState>,
leaderboard: Leaderboard
}
struct PlayerState has key, store {
id: UID,
health: u8,
score: u64
}
2. Пакетные обновления векторов/таблиц
struct DAOVault has key {
id: UID,
// Store multiple pending actions
pending_votes: Table<ID, Vote>,
pending_deposits: Table<address, Deposit>
}
public entry fun batch_process(
vault: &mut DAOVault,
ctx: &mut TxContext
) {
// Process all pending items at once
let votes = table::remove_all(&mut vault.pending_votes);
process_votes(votes);
}
3. Эпохальная обработка
struct LendingPool has key {
id: UID,
current_epoch: u64,
next_epoch_data: EpochData,
current_epoch_data: EpochData
}
public entry fun advance_epoch(pool: &mut LendingPool) {
let finished = pool.current_epoch_data;
pool.current_epoch_data = pool.next_epoch_data;
pool.next_epoch_data = new_epoch_data();
process_finished_epoch(finished);
}
Методы предотвращения конфликтов
1.Разделение на полевом уровне:
struct HighTrafficObject has key {
id: UID,
// Split into separate objects per "hot" field
stats_by_category: Table<u8, CategoryStats>
}
2.Очередь отложенного выполнения:
struct ActionQueue has key {
id: UID,
pending: VecMap<u64, Action>
}
public entry fun execute_ready_actions(
queue: &mut ActionQueue,
ready_up_to: u64
) {
// Processes actions in batches
}
3.Оптимистичное совпадение с управлением версиями:
struct Versioned has key {
id: UID,
version: u64,
data: vector<u8>
}
public entry fun update(
obj: &mut Versioned,
new_data: vector<u8>,
expected_version: u64
) {
assert!(obj.version == expected_version, EBAD_VERSION);
obj.data = new_data;
obj.version = expected_version + 1;
}
Практические примеры интерфейса командной строки
Проверка зависимостей объектов перед отправкой:
sui client inspect-transaction --serialize-unsigned <TX_BYTES>
Моделирование сценариев конкуренции:
sui move test --path <YOUR_PACKAGE> --gas-budget 10000
Краткое описание лучших практик
1.Минимизируйте мутации общих объектов: дизайн для редкой записи в общие объекты
2.Используйте дочерние объекты: состояние разложения, чтобы уменьшить количество спорных точек
3.Пакетные операции: сгруппируйте изменения в отдельные транзакции
4.Рассмотрите гибридные модели: комбинируйте принадлежащие вам объекты и время от времени совместно координируйте их
5. sui-tool replay
Мониторинг хотспотов: используйте для анализа конкуренции
Помните, что среда выполнения Sui автоматически обрабатывает некоторые параллели в своей объектной модели, но вам все равно необходимо спроектировать структуры данных так, чтобы свести к минимуму логические конфликты.
Вы должны использоватьобщий объектв Sui Move, если нескольким пользователям необходимо взаимодействовать с одним и тем же участком штата и у всех этих пользователей разные владельцы. В качестве примеров можно привести игровую арену, открытую для всех игроков, систему отслеживания голосов DAO, которая собирает голоса с разных адресов, или пул кредитования, в который каждый может внести депозит. Общие объекты доступны по всему миру, и их можно обновлять на основе консенсуса, в отличие от объектов, принадлежащих владельцу, которые привязаны к одному адресу и изменены без полного согласия.
Sui регулирует параллелизм общих объектов, требуя полного консенсуса по всем транзакциям, изменяющим эти объекты. ConflictTransaction
Когда два пользователя пытаются изменить один и тот же общий объект почти в одно и то же время, успешна только одна транзакция, а остальные отклоняются из-за ошибки. Это делает общие объекты мощными, но при их нетщательном проектировании приводит к возникновению противоречий.
Чтобы обеспечить высокий уровень параллелизма и избежать частых ConflictTransaction
ошибок, следует использоватьшаблоны проектирования, изолирующие изменяемое состояние. Вместо того чтобы хранить все изменяемые данные в одном общем объекте, разделите их на несколько дочерних объектов, каждый из которых имеет свой собственный или общий статус. Например, на игровой арене:
struct Arena has key, store {
game_id: u64,
players: vector<address>,
}
struct PlayerState has key, store {
hp: u64,
energy: u64,
}
Сделайте Arena
общий объект, но предоставьте каждому PlayerState
свой общий объект. Таким образом, разные игроки смогут самостоятельно обновлять свое состояние без конфликтов.
Другой шаблон — стратегия** «индекс + корзина»**: сохраняйте общий объект индекса, указывающий на отдельные сегменты или записи. Обращайтесь к индексу только для получения нужной записи, а затем работайте с самой записью. Это уменьшает количество совпадений между транзакциями пользователей.
Если вам нужен строгий порядок упорядочивания (например, для аукционов), используйтеручную постановку очередь, используя векторы или карты в общем объекте, но знайте, что каждая мутация по-прежнему требует согласования и может выйти из строя при загрузке. В таких случаях лучше перенести оформление заказов на внешний интерфейс или пакетную запись.
Вкратце:
- Используйте общие объекты, когда состояние должно быть доступно многим независимым пользователям.
- Не помещайте все изменяемые поля в один общий объект — разделите их на подобъекты.
- Используйте общие и динамические дочерние объекты, чтобы снизить уровень конфликтов.
- Ожидайте
ConflictTransaction
ошибок, вызванных высокой конкуренцией, и повторите попытку во внешнем интерфейсе. - По возможности отдавайте предпочтение обновлениям, доступным только для добавления, а не мутации на месте.
Когда вы проектируете с использованием общих объектов в Sui Move, вы, по сути, выбираете между удобством многопользовательского доступаириском разногласий**. Поскольку Sui использует объектно-ориентированную и ориентированную на ресурсы модель, правильный шаблон зависит от того, какой вариант использования требует совместного доступа или изолированного управления. Вот структурированный подход к этому вопросу:
###Когда использовать объекты, находящиеся в совместном пользовании
- Предметы, принадлежащие собственности**, лучше использовать, когда одному пользователю нужен полный контроль над активом (например, монетами кошелька, инвентарем игрока или уникальным NFT). Транзакции, связанные с ними, не будут конфликтовать, если один и тот же объект не будет повторно использован.
- Использование общих объектов**имеет смысл, когда нескольким пользователям необходимо читать или писать в одном и том же состоянии (например, отчет об управлении DAO, таблица лидеров на игровой арене, хранилище пула для кредитования). Они обеспечивают глобальную доступность без необходимости разрешенных переводов, но при этом сопряжены с проблемами параллельного выполнения.
###Управление параллелизмом в Sui
ConflictTransaction
Среда выполнения Sui автоматически сериализует транзакции, затрагивающие один и тот жеизменяемый общий объект. Это означает, что если два пользователя попытаются обновить один и тот же общий объект, один из них добьется успеха, а другой получит ошибку. Вам не нужно вручную кодировать блокировки или очереди — разрешение конфликтов осуществляется на уровне выполнения. Однако частые конфликты могут снизить пропускную способность, поэтому ваша задача —**проектировать макеты состояний, минимизирующие дублирование.
###Лучшие практики по предотвращению частых конфликтов
*Разделенное изменяемое состояние: вместо одного «мегаобъекта» разделите его на более мелкие дочерние объекты. Например, в хранилище, сдаваемом во временное пользование, разделяйте позицию каждого пользователя на отдельный объект или объект, находящийся в его собственности или находящийся в совместном пользовании, оставляя само хранилище в основном статичным. Это снижает конкуренцию при записи. *По возможности используйте неизменяемые поля: храните метаданные или справочные данные в неизменяемых подобъектах, чтобы транзакции, предназначенные только для чтения, не конфликтовали с транзакциями записи. *Тщательно выполняйте пакетные операции: если в проекте контракта требуется несколько операций записи в один и тот же общий объект, рассмотрите возможность объединения их в один блок транзакций во избежание многочисленных конфликтов. *Шаблоны распределения. Для таких вещей, как таблицы лидеров или DAO, распределяйте их по группам, раундам или идентификаторам, чтобы не все транзакции попадали в один и тот же путь к объекту.
###Подводные камни, на которые стоит остерегаться
*Монолитные общие объекты: объединение всех объектов в один общий объект приводит к высоким конфликтам и постоянным конфликтам под нагрузкой. *Злоупотребление общими объектами: если данные можно смоделировать как принадлежащие им данные, отдайте предпочтение этому маршруту — так дешевле и вероятность возникновения проблем меньше. *Игнорирование шаблонов доступа: если большинство взаимодействий происходит при чтении с небольшим количеством операций записи, используйте неизменные снимки, а не одно изменяемое общее состояние.
###Практический пример
Представьте себе, что вы создаете трекер голосов DAO:
*Плохая схема: каждый голос хранится в одном общем объекте, обновляемом всеми участниками.
*Лучшая схема: каждый голосующий создает собственный Vote
объект со ссылкой на предложение, в то время как общий объект DAO лишь периодически агрегирует результаты. Таким образом, параллельное голосование не будет противоречить друг другу.
###Блок транзакций
Входные данные → Пользователи совершают транзакции с общими или находящимися в собственности объектами. Процесс → Среда выполнения Sui сериализует транзакции в одном и том же изменяемом общем объекте. Результат → Успешные записи фиксируются, в других возникают конфликтные ошибки; разделение объектов снижает вероятность конфликтов.
Great questions—this is exactly the crux of building “high-fanout” apps on Sui. Here’s a practical playbook you can follow.
🧭 When to use a shared object (vs owned)
Use a shared object only when multiple independent parties must mutate the same piece of state and you need one canonical result (e.g., AMM pool reserves, an arena’s match registry, a DAO proposal’s tally). Prefer owned objects when the state is per-user, per-position, or per-item and can evolve independently (inventories, user balances, open positions).
Rule of thumb: put the coordination surface in a shared object, and everything else in owned objects that can run in parallel.
⚙️ What Sui does with concurrent access
- Any tx that mutates a shared object goes through consensus and is totally ordered. Conflicting writes to the same fields are serialized; others proceed in parallel.
- You don’t manually lock; you design to avoid hotspots. Conflicts show up as
ConflictTransaction
when many txs try to bump the same version.
🏗️ High-concurrency design patterns (with Move tips)
1) Root-manager + owned positions
Keep a minimal shared root; put user/position state in owned objects so deposits/claims mostly touch owned data.
module example::vault {
use sui::tx_context::TxContext;
struct Vault has key { /* config only; no growing vectors */ }
struct Position has key { owner: address, /* state */ }
/// Shared root only needed to mint/close positions or checkpoint.
public entry fun open_position(v: &mut Vault, ctx: &mut TxContext): Position { /* ... */ }
/// Hot path touches owned Position only → parallel.
public entry fun deposit(pos: &mut Position, amount: u64) { /* ... */ }
}
Why it scales: most traffic avoids the shared root altogether.
2) Shard by key (dynamic fields / tables)
Instead of one big shared map, create N shard objects (shared) under a registry and route by hash(key) % N
. Each shard is a separate contention domain.
/// registry is shared; it stores IDs of shard objects
struct Registry has key { shards: vector<ID> }
/// choose shard once and keep it stable for that key
fun shard_for(reg: &Registry, key: &vector<u8>): ID { /* hash(key) % len */ }
Tip: don’t update the registry on every user op; mutate only the target shard.
3) Dynamic fields on a shared “anchor”, not growing vectors
Avoid vector.push
on a shared object (resizes = conflicts). Use dynamic fields (key → value) so each entry mutates independently.
SharedAnchor
└─ df[key=user] = tiny record (or pointer to owned object)
Move APIs: sui::dynamic_field::{add, borrow_mut, remove}
.
4) Two-phase “ticket” pattern
Have the shared object mint a ticket/capability (owned) that authorizes a later operation done off the hot path.
- Light touch on shared root → mint
Ticket
. - User completes heavy work by presenting the
Ticket
and mutating only owned/child objects.
Reduces churn on the shared root, and gives you idempotency (ticket can be one-time-use).
5) Append-only events, deferred aggregation
If you’re tempted to keep a total_*
counter on the shared root (a hotspot), emit events on each action and aggregate off-chain or in a periodic checkpoint entry that rolls up per-shard totals.
6) Split mutable fields into sub-objects
If one field changes much more frequently (e.g., queue head), peel it into its own child object (owned or shared as needed). Then updates don’t bump the root’s version.
🧪 Avoiding ConflictTransaction
in practice
- Keep the cut set small: Each entry function should touch as few objects as possible.
- No growing vectors on shared roots; use dynamic fields or sharded children.
- Stable routing: Deterministic key→shard mapping; never rehash live keys.
- Idempotency: Use tickets/nonces so retries don’t double-apply.
- Batch carefully: If you must touch multiple entries atomically, use a PTB—but keep it within a single shard when possible.
- Backoff & retry: On the client, exponential backoff for known conflict aborts.
🔍 Minimal conflict checklist
- Shared root is configuration + pointers only.
- Hot paths mutate owned positions or sharded children.
- Per-user/per-item state is not inside the root.
- No
vector.push
on shared; use dynamic fields. - Periodic checkpoint function consolidates, not every tx.
🛡️ Security & correctness notes
- Gate privileged ops with capabilities (e.g.,
AdminCap
,MintCap
); store caps in owned objects, not globals. - Validate invariants in shared entry points (sum of shard totals, proposal status transitions, etc.).
- Emit events for auditability; they are cheap and conflict-free.
Quick templates by use case
- Game arena: Shared
Arena
(config/match index) + ownedPlayer
/Loadout
. Match joins go toShard[hash(match_id)]
. - DAO voting: Shared
Proposal
(immutable metadata) + dynamic fields per voter or ownedBallot
tickets. Tally via periodic checkpoint. - Lending vault: Shared
Registry
+ ownedPosition
s; price/oracle reads are immutable; rebalances via sharded pools.
Знаете ответ?
Пожалуйста, войдите в систему и поделитесь им.
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
Заработай свою долю из 1000 Sui
Зарабатывай очки репутации и получай награды за помощь в развитии сообщества Sui.

- Почему BCS требует точного порядка полей для десериализации, когда структуры Move содержат именованные поля?65
- «Ошибки проверки нескольких источников» в публикациях модуля Sui Move — автоматическое устранение ошибок55
- Сбой транзакции Sui: объекты, зарезервированные для другой транзакции49
- Как максимизировать прибыль, держа SUI: стейкинг и ликвидный стейкинг313
- Ошибка Sui Move — невозможно обработать транзакцию Не найдено действительных газовых монет для транзакции315