Publication
Partagez vos connaissances.
Modèles de conception et gestion de la simultanéité pour les objets partagés dans Sui Move
J'essaie de trouver le bon modèle architectural lorsque je travaille avec des objets partagés dans Sui Move, en particulier lorsque plusieurs utilisateurs doivent interagir avec eux simultanément (par exemple, dans une arène de jeu, un outil de suivi des votes DAO ou un coffre de prêt).
J'ai lu que les objets partagés peuvent entraîner des problèmes de synchronisation, mais je ne suis toujours pas clair sur :
- À quel moment dois-je utiliser un
shared
objet exactementowned
? - Comment Sui gère-t-il les tentatives de transaction simultanées sur le même objet partagé ? Dois-je mettre les objets en file d'attente et les verrouiller manuellement ?
- Quelle est la meilleure pratique pour concevoir des modules qui prennent en charge une simultanéité élevée tout en évitant les
ConflictTransaction
erreurs fréquentes ? - Dois-je faire quelque chose de spécial (comme diviser des champs mutables en sous-objets) pour réduire les conflits ?
- Sui
- Architecture
- NFT Ecosystem
- Move
Réponses
13Lorsque vous créez une DApp sur Sui où plusieurs utilisateurs doivent interagir avec le même État, comme dans une arène de jeu, un protocole de prêt ou un DAO, vous devez utiliser desobjets partagésau lieu de ceux que vous possédez. Les objets partagés sont accessibles au public et modifiables, ce qui signifie que tout le monde peut y appeler des fonctions de saisie tant qu'ils se trouvent dans le graphe d'objets global. En revanche, les objets possédés sont privés pour un utilisateur et sont idéaux pour les actifs personnels tels que les portefeuilles ou les stocks. Vous devez donc utiliser un objet partagé lorsque les mises à jour d'état doivent être visibles et utilisables par de nombreux utilisateurs à la fois.
Sui gère les transactions simultanées sur des objets partagés via un mécanisme appelévalidation de l'ordre causal, qui vous oblige à fournir explicitement la dernière version connue d'un objet partagé. Si deux utilisateurs tentent de modifier le même objet partagé en même temps avec des versions obsolètes, l'un d'eux y parviendra tandis que les autres échoueront avec une ConflictTransaction
erreur. Sui ne met pas en file d'attente ni ne verrouille les objets partagés de manière native. Vous devez donc concevoir vos modules Move de manière à minimiser les écritures qui se chevauchent. L'un des meilleurs moyens de réduire les conflits est deconcevoir en fonction du parallélisme. Par exemple, au lieu de stocker tous les états modifiables dans l'objet partagé racine, vous pouvezdiviser les champs à forte contention en objets enfants distincts. Chacun de ces enfants peut ensuite être écrit indépendamment, ce qui réduit le risque de conflits de transactions.
Une bonne pratique consiste à conserver l'objet partagé principal sous forme de répertoire et à déplacer des états granulaires et fréquemment mis à jour, tels que les scores des joueurs, les votes ou les soldes des prêts, vers des champs dynamiques ou des sous-objets plus petits. De cette façon, les utilisateurs mettent à jour uniquement la partie spécifique dont ils ont besoin, et non l'ensemble de l'objet partagé. Il est également judicieux de séparer les composants lourds en lecture et en écriture. En outre, vous devez créer des flux de transactions clairs et déterministes qui utilisent toujours la version la plus récente des objets partagés et réessayez la logique permettant aux clients de gérer les transactions échouées.
Pour en savoir plus sur la conception d'objets partagés et l'atténuation des conflits, consultez la documentation Sui ici : https://docs.sui.io/concepts/objects#shared-objects.
Si vous gérez quelque chose comme un outil de suivi des votes, voici un exemple de bloc de transactions simplifié pour réduire les conflits :
const tx = new TransactionBlock();
tx.moveCall({
target: `$ {packageId} ::vote_tracker : :cast_vote`,
arguments : [
tx.SharedObject (VoteTrackerID),//référence à un objet partagé
tx.pure (voterId),//objet possédé ou clé publique
tx.pure (ProposalId),//données pures
tx.pure (Choix de vote)
]
}) ;
Dans Sui Move, lesobjets partagés(marqués d'unkey + store
) sont essentiels pour l'interaction multi-utilisateurs mais nécessitent une conception minutieuse de la simultanéité. Utilisez-les lorsque l'état doit être globalement modifiable (par exemple, jeux, DAO), tandis que les objets possédés/immuables conviennent à des scénarios mono-utilisateur. Sui sérialise automatiquement les transactions par objet partagé, mais des écritures fréquentes peuvent provoquer des ConflictTransaction
erreurs. Réduisez ce problème endivisant les champs activésen objets enfants distincts (par exemple, un par utilisateur) ou en effectuant des mises à jour par lots. Pour un débit élevé, adoptez desmodèles de source d'événements : stockez les actions sous forme d'événements immuables et agrégez l'état périodiquement. Minimisez toujours les champs partagés mutables et préférez les échanges atomiques aux transfer::share_object
mutations directes.
Dans Sui Move, la gestion efficace des objets partagés et de la simultanéité nécessite une conception minutieuse pour éviter les conditions de concurrence et les conflits. Voici un aperçu des meilleures pratiques et des modèles architecturaux :
1.Quand utiliser des objets partagés par rapport à des objets possédés :
*Objets partagés : à utiliser lorsque plusieurs utilisateurs doivent interagir simultanément avec le même objet (par exemple, état de jeu partagé, suivi des votes DAO). *Objets possédés : à utiliser lorsque l'objet est spécifique à un seul utilisateur ou à un seul compte, ce qui permet d'éviter l'état partagé et de réduire les problèmes de simultanéité.
###2.Gestion simultanée des transactions dans Sui :
- Sui gère automatiquement la concurrence en utilisantTransaction Lockspour empêcher les modifications simultanées du même objet.
- Vousn' avez pasbesoin de mettre en file d'attente ou de verrouiller manuellement les objets partagés, car Sui applique un verrouillage au niveau de l'objet. Cependant,vous risquez d'obtenir des erreurs ConflictTransactionsi plusieurs transactions entrent en conflit sur le même objet.
3.Meilleures pratiques pour une simultanéité élevée :
*Minimiser les contentions : divisez les champs mutables en sous-objets distincts pour permettre des mises à jour parallèles de différentes parties de l'objet. *Évitez les hotspots : répartissez l'état fréquemment modifié sur plusieurs objets (par exemple, au lieu d'avoir un seul registre partagé, divisez-le en plusieurs compartiments ou comptes). *Versioning : utilisez des objets versionnés ou créez de nouveaux objets pour suivre les mises à jour au lieu de muter le même objet à plusieurs reprises.
##4.Gestion des contentions :
- Envisagez dediviser les champs mutables en objets plus petitspour réduire les conflits. Cela permet de mettre à jour simultanément différentes parties de l'objet, réduisant ainsi les risques de conflits.
- Utiliseztransactions atomiquespour regrouper les actions associées en une seule, en garantissant la cohérence entre les objets associés.
Exemple :
Si vous avez unoutil de suivi des votespour un DAO :
- Au lieu de stocker tous les votes dans un seul objet partagé, divisez-les en plusieurs objets (par exemple, un par proposition), ce qui permet des mises à jour parallèles pour chaque proposition tout en réduisant les conflits.
Conclusion :
Pour une simultanéité élevée, minimisez les conflits en distribuant l'état, en utilisant des sous-objets et en tirant parti de la gestion automatique des transactions de Sui. Assurez-vous de bien comprendre vos modèles d'accès et de structurer les objets afin de minimiser les points de conflit.
Comprendre les modèles de conception et la gestion de la simultanéité pour les objets partagés dans Sui Move
Lorsque vous traitez desobjets partagésdansSui Move, la gestion de la simultanéité devient essentielle, car plusieurs utilisateurs peuvent avoir besoin d'interagir simultanément avec le même objet. Cela est particulièrement vrai pour des cas d'utilisation tels queles arènes de jeu, lesoutils de suivi des votes DAOet lescoffres-forts de prêt, où une forte simultanéité est attendue. Le réseau Sui fournit certaines fonctionnalités qui aident à gérer la simultanéité, mais il nécessite tout de même une conception minutieuse pour éviter les pièges courants, tels que leserreurs de transaction Conflict.
1.Quand utiliser des objets partagés par rapport à des objets possédés
*Objets possédés :
-
Un objet estpossédés'il est géré par une seule adresse, qui peut le transférer ou le modifier. *Utilisez des objets possédéslorsque vous vous attendez à ce qu'une seule entité contrôle un objet et interagisse avec lui. Par exemple, si vous avez un portefeuille contenant des pièces, chaque portefeuille est propriétaire de ses propres pièces. *Objets partagés :
-
Les objets partagés peuvent être consultés et modifiés par plusieurs adresses simultanément. Sui vous permet de définir des objets commepartagésen les rendant modifiables et en fournissant un accès à plusieurs parties. *Utilisez des objets partagéspour les scénarios dans lesquels plusieurs utilisateurs ou adresses doivent interagir avec le même objet, tels que :
*Suivi des votes DAO : plusieurs utilisateurs peuvent voter pour le même objet. *Coffres-forts de prêt : plusieurs utilisateurs peuvent prêter et emprunter dans le même coffre-fort. *Arènes de jeu : plusieurs utilisateurs interagissent avec l'état du jeu en même temps.
Considération principale : Les objets partagés doivent être utilisés avec précaution, car ils peuvent introduire unecontention, c'est-à-dire des situations dans lesquelles plusieurs transactions tentent d'accéder au même objet et de le modifier en même temps.
###2.Tentatives de simultanéité et de transaction sur des objets partagés
Sui garantit que lestransactionssimultanées sur le mêmeobjet partagésont gérées correctement en appliquant l'isolation transactionnelle. Si plusieurs transactions tentent de muter le même objet partagé en même temps, l'une d'entre elleséchoueren raison d'unecontention.
Lorsqu'une transaction tente de modifier un objet partagé qui est déjà modifié par une autre transaction, Sui renvoie une erreurConflictTransaction. Cependant,Sui gère la majeure partie de la gestion de la simultanéité en interne, et vousn' avez pas besoin de mettre en file d'attente ou de verrouillermanuellement les objets. Vous devez plutôt concevoir votre contrat de manière à minimiser les litiges et à éviter les situations où deux transactions entrent fréquemment en conflit.
3.Meilleures pratiques pour une simultanéité élevée et la réduction des erreurs de transaction conflictuelles
Pourconcevoir des modulescapables de gérer une simultanéité élevée et d'éviter les fréquentes erreursConflictTransaction, suivez ces bonnes pratiques :
a.Minimiser les points de contention :
*Limiter l'accès modifiable : limitez autant que possible le nombre de champs modifiables dans les objets partagés. Chaque champ mutable introduit un point de discorde potentiel. *Utilisez des objets détenus pour des données indépendantes : au lieu de tout partager, stockez les données indépendantes dans des objets détenus. Par exemple, si vous disposez de données spécifiques à l'utilisateur (comme le solde), stockez-les dans un objet qui vous appartient plutôt que dans un objet partagé.
b.Utilisez le modèle de « partitionnement par État » :
-
Divisez votre objet partagé enplusieurs sous-objetspour réduire les conflits. Par exemple, au lieu d'avoir un seul objet partagé qui suit l'intégralité de l'état du jeu, vous pouvez le diviser en plusieurs sous-objets :
-
Un pour l'état de chaquejoueur.
-
Un pour lesparamètres du jeu.
-
Un pourles données du leaderboard.
-
De cette façon, les transactions liées à différentes parties du système peuvent être effectuées simultanément sans se bloquer les unes les autres.
c.Opérations par lots :
- Lorsque vous travaillez avec des objets partagés, regroupez vos mises à jour afin de réduire le nombre de transactions devant interagir avec l'objet. Cela peut permettre d'éviter de fréquents conflits. *Utilisez des collectionscomme des vecteurs ou des ensembles pour gérer plusieurs mises à jour en une seule transaction.
d.Utilisez les opérations atomiques :
- Dans la mesure du possible, concevez vos modules de manière à utiliser les opérations atomiques dans la mesure du possible. Par exemple, au lieu d'avoir des transactions distinctes pour vérifier une condition puis mettre à jour un champ, regroupez les vérifications et les mises à jour en une seule opération atomique.
e.Réessayez Logique :
- Bien que Sui gère les nouvelles tentatives en interne, vous pouvez implémenter une logique de nouvelle tentative au niveau de l'application pour gérer les erreurs de contention occasionnelles. Par exemple, si une
ConflictTransaction
erreur survient, vous pouvez simplement réessayer la transaction ou la mettre en file d'attente pour une exécution ultérieure.
##4.Réduire les conflits en divisant les champs mutables en sous-objets
Il s'agit d'une pratique hautement recommandée. Lorsqu'il s'agit d'objets partagés, plusil y a de champsmutablesdans un objet partagé, plus il y a de chances que deux transactions tentent de muter le même champ en même temps.
*Exemple 1 : Si vous avez un objet partagé représentant uncoffre de prêt, divisez-le en sous-objets :
- Un pour lesdépôts : suivez les dépôts individuels séparément.
- Un pour lesprêts : suivez les prêts individuels séparément.
- Un pourl'état du coffre : suivez les informations générales sur l'état (par exemple, la valeur totale, le taux d'intérêt).
Ainsi, une transaction qui modifie un sous-objet (par exemple, le sous-objetprêt) n'entre pas en conflit avec une transaction qui en modifie un autre (par exemple, le sous-objetdépôt).
*Exemple 2 : Dans unearène de jeu :
- Divisez l'état du jeu en sous-objets pour chaque joueur, l'état du jeu et les statistiques de combat. Cela réduit le risque de conflits lorsque différents joueurs interagissent avec leurs états de jeu individuels.
En divisant les champs modifiables ensous-objets, vous réduisez la probabilité que plusieurs utilisateurs tentent de modifier le même objet simultanément.
##5.Autres techniques pour gérer la simultanéité dans Sui
*Verrouillage (verrous explicites) : Bien que Sui ne vous oblige pas à gérer manuellement les verrous, dans certains cas, vous souhaiterez peut-être appliquer desverrouillageà l'aide d'objets de verrouillage(objets séparés qui garantissent qu'une seule transaction peut accéder à une ressource particulière à la fois).
*Isolation temporale : Si vos objets ne changent que de temps en temps, pensez à introduire uneisolation temporelle. Par exemple, si vous gérez un coffre-fort ou un système de vote, définissez despériodes de voteou desfenêtres de transactionpour limiter les interactions pendant certaines périodes.
##6.Exemple de code pour gérer la simultanéité avec des sous-objets
Voici un exemple illustrant comment réduire les conflits en divisant uncoffre de prêten sous-objets plus petits :
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;
}
}
Résumé
*Utilisez des objets partagéslorsque plusieurs utilisateurs doivent interagir simultanément avec le même objet (par exemple, votes DAO, état du jeu, coffres de prêt). *Minimisez les contentionsen divisant les grands objets partagés en sous-objets plus petits et en réduisant le nombre de champs modifiables. *Évitez les erreurs ConflictTransactionfréquentes en suivant les meilleures pratiques telles que le partitionnement d'état, les opérations par lots et l'utilisation d'opérations atomiques.
- LaLogique des réessayeset lecontrôle de simultanéité optimistepeuvent être utilisés pour gérer les conflits avec élégance. Lemodèle transactionnelet larésolution des conflitsde * Sui sont robustes, mais laconceptionde vos objets partagés est essentielle pour garantir un accès simultané efficace.
En suivant ces principes de conception, vous serez en mesure de gérer une simultanéité élevée dans vos modules basés sur Move tout en évitant les pièges habituels tels que lesconflitset leserreurs de transaction.
Utilisezobjets partagéspour accéder à plusieurs rédacteurs (par exemple, jeux, DAO). Principaux modèles :
1.Détenu ou partagé
- Possédé : rédacteur unique (plus rapide).
- Partagé : écritures simultanées (gaz plus élevé).
2.Gestion de la simultanité
- Sui séquence automatiquement les TX des objets partagés (pas de verrouillage manuel).
- Divisez les données sensibles en sous-objets (par exemple, un par joueur) pour réduire les conflits.
3.Atténuation des conflits
- Isolez les zones à fort trafic (par exemple
Table<ID, PlayerData>
). - Utilisez des PTB pour les opérations atomiques multi-objets.
Surveillez :
- ConflictTransaction
: Données fractionnées ou mises à jour par lots.
- Des pics de gaz sur les objets partagés.
- (L'environnement d'exécution de Sui gère les conflits : optimisez via le partitionnement des données. ) *
Utilisezobjets partagés(transfer::share_object
) lorsque plusieurs utilisateurs doivent muter le même objet (par exemple, coffre, DAO, état du jeu). Utilisezpossédédans le cas contraire.
TransactionLockConflict
Sui gère la simultanéité viaNarwhal & Tusk : les transactions conflictuelles sur un objet partagé sont sérialisées : une seule réussit par tour ; les autres échouent avec. Aucun verrouillage manuel n'est nécessaire, maisvous devez concevoir pour les récupérations.
Meilleures pratiques :
- Minimisez l'état modifiable des objets partagés ; divisez les hotspots en sous-objets distincts (par exemple, des partages de coffres-forts par utilisateur).
- Utilisez
VecMap
ouTable
pour des mappages évolutifs. - Évitez les longs calculs dans les fonctions partagées.
- Émet des événements au lieu de stocker des états éphémères.
- Pour les systèmes à forte contention, utilisez des schémasbatchingoucommit-reveal pour réduire les conflits.
Les objets partagés sont accessibles dans le monde entier mais génèrent plus de gaz et de conflits. Optimisez l'idempotence et réessayez la logique dans le code client.
Pour lesobjets partagésdans Sui Move, utilisez ces modèles pour gérer la simultanéité :
####1. Partagé ou possédé ?
-Objet partagé (key + store
) :
- À utiliser pourétat global(par exemple, jeux, DAO).
- Permet lesécritures parallèles(contrairement aux TX sérialisés d'EVM).
struct GameArena has key, store { id: UID, players: vector<address> }
-Objet possédé :
- À utiliser pourles données spécifiques à l'utilisateur(par exemple, les NFT, les portefeuilles).
struct PlayerInventory has key { id: UID, items: vector<Item> }
####2. Gestion de la simultanité -Pas de verrouillage manuel : Suirésout les conflits automatiquement(contrairement à EVM). -Diviser la contention : divisez les objets partagés ensous-objets plus petits(par exemple, par joueur ou par fragment).
struct PlayerScore has key, store { id: UID, points: u64 } // Less contention
####3. Réduire les ConflictTransaction
erreurs
-Isoler les écritures : mettez à jourles différents champsdans des TXs séparés.
-À utiliser &mut
judicieux : évitez les mutations générales.
public entry fun update_score(
arena: &mut GameArena,
player: address,
points: u64
) { /* ... */ } // Only touches 1 player’s data
####4. Meilleures pratiques -Mises à jour par lots : regroupez les opérations non conflictuelles (par exemple, les votes dans un DAO). -Event-Driven : émettez des événements au lieu de modifier l'état lorsque cela est possible.
struct VoteEvent has copy, drop { voter: address, choice: u8 }
Utilisez des objets partagés pour accéder à plusieurs rédacteurs (par exemple, des jeux, des DAO). Principaux modèles :
Détenu ou partagé
Propriétaire : rédacteur unique (plus rapide). Partagé : écritures simultanées (gaz plus élevé). Gestion de la simultanéité
Sui séquence automatiquement les TX des objets partagés (pas de verrouillage manuel). Divisez les données sensibles en sous-objets (par exemple, un par joueur) pour réduire les conflits. Atténuer les conflits
Isolez les champs à fort trafic (par exemple, Tableau<ID, PlayerData>). Utilisez des PTB pour les opérations atomiques multi-objets. Surveillez :
ConflictTransaction : données fractionnées ou mises à jour par lots. Des pics de gaz sur des objets partagés. (L'environnement d'exécution de Sui gère les conflits : optimisez via le partitionnement des données.)
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
Objets partagés et objets possédés : quand utiliser chacun
Utilisez des objets partagés lorsque :
- Plusieurs utilisateurs doivent muter le même état
- L'objet représente une ressource publique (comme une arène de jeu ou un DAO)
- Vous avez besoin de modèles d'accès sans autorisation
Utilisez les objets que vous possédez lorsque :
- Une seule adresse doit contrôler l'objet
- Vous souhaitez tirer pleinement parti de l'exécution parallèle de Sui
- Les objets représentent des actifs spécifiques à l'utilisateur
Stratégies de gestion de la simultanéité
1. Modèle de sous-objet (réduire la contention)
Divisez les champs fréquemment mis à jour en objets distincts :
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. Mises à jour par lots avec vecteurs/tableaux
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. Traitement basé sur Epoch
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);
}
Techniques d'évitement des conflits
1.Partitionnement au niveau du champ :
struct HighTrafficObject has key {
id: UID,
// Split into separate objects per "hot" field
stats_by_category: Table<u8, CategoryStats>
}
2.File d'attente d'exécution différée :
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.Concurrence optimiste avec la gestion des versions :
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;
}
Exemples pratiques de CLI
Vérification des dépendances des objets avant la soumission :
sui client inspect-transaction --serialize-unsigned <TX_BYTES>
Simulation de scénarios de contention :
sui move test --path <YOUR_PACKAGE> --gas-budget 10000
Résumé des meilleures pratiques
1.Minimiser les mutations d'objets partagés : conception pour les écritures peu fréquentes sur des objets partagés
2.Utiliser des objets enfants : état de décomposition pour réduire les points de contention
3.Opérations par lots : Regroupez les modifications liées en transactions uniques
4.Envisagez des modèles hybrides : combinez des objets que vous possédez avec une coordination partagée occasionnelle
5. sui-tool replay
Surveiller les hotspots : à utiliser pour analyser les conflits
N'oubliez pas que le moteur d'exécution de Sui gère automatiquement une certaine concurrence via son modèle objet, mais que vous devez tout de même concevoir vos structures de données pour minimiser les conflits logiques.
Vous devez utiliser unobjet partagédans Sui Move lorsque plusieurs utilisateurs doivent interagir avec le même élément d'état et que ces utilisateurs ne sont pas tous sous le même propriétaire. Les exemples incluent une arène de jeu ouverte à tous les joueurs, un outil de suivi des votes DAO qui collecte les votes à différentes adresses ou un pool de prêt dans lequel tout le monde peut effectuer des dépôts. Les objets partagés sont accessibles dans le monde entier et peuvent être mis à jour par consensus, contrairement auxobjets possédés, qui sont liés à une adresse unique et modifiés sans consensus total.
Sui gère la simultanéité sur les objets partagés en exigeant un consensus total pour toute transaction qui les modifie. ConflictTransaction
Lorsque deux utilisateurs tentent de muter le même objet partagé à peu près en même temps, une seule transaction aboutit ; les autres sont rejetées avec une erreur. Cela rend les objets partagés puissants, mais crée également des problèmes de contention lorsqu'ils ne sont pas conçus avec soin.
Pour prendre en charge la haute simultanéité sans rencontrer d'ConflictTransaction
erreurs fréquentes, vous devez utiliserdes modèles de conception qui isolent l'état mutable. Au lieu de stocker toutes les données modifiables dans un seul objet partagé, divisez-le en plusieurs objets enfants, chacun ayant sa propre propriété ou son propre statut partagé. Par exemple, dans une arène de jeu :
struct Arena has key, store {
game_id: u64,
players: vector<address>,
}
struct PlayerState has key, store {
hp: u64,
energy: u64,
}
Faites en sorte qu'il soit Arena
partagé, mais donnez à chacun PlayerState
son propre objet partagé. De cette façon, les différents joueurs peuvent mettre à jour leur état indépendamment sans entrer en conflit.
Un autre modèle est la stratégie** « index + compartiment »** : conservez un objet d'index partagé qui pointe vers des compartiments ou des entrées individuels. Accédez à l'index uniquement pour récupérer la bonne entrée, puis opérez sur l'entrée elle-même. Cela réduit le chevauchement entre les transactions des utilisateurs.
Si vous avez besoin d'un ordre strict (par exemple, pour les enchères), implémentez lamise en file d'attente manuelleà l'aide de vecteurs ou de cartes à l'intérieur de l'objet partagé, mais sachez que chaque mutation nécessite toujours un consensus et peut échouer en cas de chargement. Dans ces cas, envisagez de décharger la commande vers le frontend ou de regrouper les écritures par lots.
En résumé :
- Utilisez des objets partagés lorsque de nombreux utilisateurs indépendants doivent accéder à l'état.
- Évitez de placer tous les champs modifiables dans un seul objet partagé, divisez-les en sous-objets.
- Utilisez des objets enfants partagés et dynamiques pour réduire les taux de conflit.
- Attendez-vous à
ConflictTransaction
des erreurs en cas de forte contention et réessayez sur le frontend. - Préférez les mises à jour uniquement en ajout dans la mesure du possible, plutôt qu'une mutation sur place.
Lorsque vous concevez avec des objets partagés dans Sui Move, vous devez essentiellement choisir entrela commodité d'un accès multi-utilisateuret lerisque de contention. Étant donné que Sui utilise un modèle centré sur les objets et orienté vers les ressources, le bon modèle dépend de la question de savoir si votre cas d'utilisation nécessite un accès collaboratif ou un contrôle isolé. Voici une façon structurée d'y penser :
###Quand utiliser des objets partagés par rapport à des objets possédés
- Lesobjets possédéssont préférables lorsqu'un seul utilisateur a besoin du contrôle total d'un actif (par exemple, les pièces d'un portefeuille, l'inventaire d'un joueur ou un NFT unique). Les transactions les impliquant n'entreront pas en conflit à moins que le même objet ne soit réutilisé. *Les objets partagésont du sens lorsque plusieurs utilisateurs doivent lire ou écrire dans le même état (par exemple, un enregistrement de gouvernance DAO, un classement d'une arène de jeu, un coffre de prêt). Ils permettent un accès mondial sans avoir besoin de transferts autorisés, mais ils présentent des problèmes de simultanéité.
###Gestion de la simultanéité dans Sui
ConflictTransaction
Le runtime de Sui sérialise automatiquement les transactions qui touchent le mêmeobjet partagé mutable, ce qui signifie que si deux utilisateurs essaient de mettre à jour le même objet partagé, l'un réussira et l'autre obtiendra une erreur. Il n'est pas nécessaire de coder manuellement les verrous ou les files d'attente : la résolution des conflits est gérée au niveau de la couche d'exécution. Cependant, des conflits fréquents peuvent dégrader le débit. Votre travail consiste donc àconcevoir des dispositions d'état qui minimisent les chevauchements.
###Meilleures pratiques pour éviter les conflits fréquents
*État mutable divisé : au lieu d'un seul « méga-objet », décomposez-le en objets enfants plus petits. Par exemple, dans un coffre de prêt, séparez la position de chaque utilisateur en fonction de son propre objet ou d'un objet partiellement partagé, laissant le coffre-fort lui-même pratiquement statique. Cela réduit les conflits d'écriture. *Utilisez des champs immuables dans la mesure du possible : stockez les métadonnées ou les données de référence dans des sous-objets immuables afin que les transactions qui ne font que lire n'entrent pas en collision avec celles qui écrivent. *Opérations par lots soigneusement : Si la conception de votre contrat nécessite plusieurs écritures sur le même objet partagé, pensez à les regrouper dans un seul bloc de transactions pour éviter de multiples conflits. *Modèles de partition : pour des éléments tels que les classements ou les DAO, répartissez l'état des fragments par groupe, tour ou identifiant afin que toutes les transactions n'atteignent pas exactement le même chemin d'objet.
###Les pièges à surveiller
*Objets partagés monolithiques : Tout placer dans un seul objet partagé entraîne de fortes tensions et des conflits constants lors de la charge. *Utilisation excessive d'objets partagés : si les données peuvent être modélisées comme si elles étaient détenues, privilégiez cette voie, car elle est moins coûteuse et moins susceptible de provoquer un engorgement. *Ignorer les modèles d'accès : si la plupart des interactions sont lues avec peu d'écritures, concevez autour d'instantanés immuables plutôt que d'un état partagé mutable.
###Exemple pratique
Imaginez créer un outil de suivi des votes DAO :
*Mauvais modèle : un seul objet partagé stockant chaque vote, mis à jour par tous les participants.
*Meilleur modèle : chaque électeur crée un Vote
objet appartenant faisant référence à la proposition, tandis que l'objet DAO partagé ne fait qu'agréger les résultats périodiquement. De cette façon, le vote parallèle n'entre pas en conflit.
###Bloc de transaction
Entrées → Les utilisateurs soumettent des transactions pour des objets partagés ou détenus. Processus → Le runtime de Sui sérialise les transactions sur le même objet partagé mutable. Résultat → Les écritures réussies sont validées, d'autres génèrent des erreurs de conflit ; le fractionnement des objets réduit les risques de conflits.
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.
Connaissez-vous la réponse ?
Veuillez vous connecter et la partager.
Sui is a Layer 1 protocol blockchain designed as the first internet-scale programmable blockchain platform.
Gagne ta part de 1000 Sui
Gagne des points de réputation et obtiens des récompenses pour avoir aidé la communauté Sui à se développer.

- Pourquoi BCS exige-t-il un ordre de champs exact pour la désérialisation alors que les structures Move ont des champs nommés ?65
- « Erreurs de vérification de sources multiples » dans les publications du module Sui Move - Résolution automatique des erreurs55
- Échec de la transaction Sui : objets réservés pour une autre transaction49
- Comment maximiser la détention de profits SUI : Sui Staking contre Liquid Staking313
- Erreur Sui Move - Impossible de traiter la transaction Aucune pièce de gaz valide n'a été trouvée pour la transaction315