La structure des composants d'Arbitrum interprétée par l'ancien ambassadeur technique d'Arbitrum (1ère partie)

AvancéJan 08, 2024
Cet article tente de combler cette lacune en fournissant une compréhension du mécanisme opérationnel de l'Arbitrum, en se concentrant sur l'interprétation technique de l'Arbitrum One.
La structure des composants d'Arbitrum interprétée par l'ancien ambassadeur technique d'Arbitrum (1ère partie)

Étant donné que la communauté chinoise manque d'interprétation professionnelle des articles ou des documents relatifs aux protocoles de la couche 2, en particulier pour Arbitrum et OP Rollup, cet article vise à combler cette lacune en expliquant le mécanisme opérationnel d'Arbitrum. En raison de la complexité d'Arbitrum lui-même, le texte complet, même après avoir été simplifié autant que possible, dépasse encore 10 000 mots. Il est donc divisé en deux parties et il est recommandé de le conserver et de le partager en tant que matériel de référence".

Vue d'ensemble du séquenceur rollup

Le principe du Rollup peut être résumé en deux points :

Optimisation des coûts : Transférez la plupart des tâches de calcul et de stockage à la couche 2, qui est exploitée sous L1. L2 fonctionne principalement sur un seul serveur, appelé séquenceur/opérateur, formant une chaîne distincte.

Le séquenceur apparaît presque comme un serveur centralisé en termes de perception, abandonnant la décentralisation dans la "trinité impossible de la blockchain" pour obtenir des avantages en termes de TPS et de coût. Les utilisateurs peuvent utiliser L2 pour traiter les instructions de transaction au lieu d'Ethereum, avec des coûts bien inférieurs à ceux des transactions sur Ethereum.

(Source : BNB Chain)

Assurance de la sécurité : Le contenu des transactions et l'état post-transactionnel sur L2 sont synchronisés avec Ethereum L1, et leur validité est vérifiée par des contrats de transition d'état. Parallèlement, Ethereum conserve l'historique de L2, de sorte que même si le séquenceur tombe en panne de manière permanente, d'autres personnes peuvent reconstituer l'état complet de L2 grâce aux enregistrements d'Ethereum.

Fondamentalement, la sécurité de Rollup repose sur Ethereum. Si le séquenceur ne connaît pas la clé privée d'un compte, il ne peut pas initier de transactions au nom de ce compte ou manipuler le solde des actifs du compte (même s'il tentait de le faire, il serait rapidement détecté).

Alors que le séquenceur, en tant que plaque tournante, a un aspect centralisé, dans les solutions de rollup matures, le séquenceur centralisé ne peut s'engager que dans des activités malveillantes douces, telles que la censure des transactions ou les plantages malveillants. Dans un scénario idéal de rollup, il existe des mesures correspondantes pour limiter de telles actions, telles que des retraits obligatoires ou des preuves de séquençage pour les mécanismes anti-censure.

(Le protocole Loopring prévoit une fonction de retrait forcé dans le code source du contrat sur L1 pour que les utilisateurs puissent l'appeler).

Les mécanismes de vérification de l'état visant à empêcher les actions malveillantes des séquenceurs de rollup sont divisés en deux catégories : la preuve de fraude et la preuve de validité. Les solutions de rollup utilisant la preuve de fraude sont appelées rollup OP (Optimistic Rollup, OPR), tandis que celles qui utilisent la preuve de validité sont souvent appelées rollup ZK (Zero-knowledge Proof Rollup, ZKR) plutôt que rollup de validité en raison du bagage historique.

Arbitrum One est un OPR typique, déployé sur L1 avec des contrats qui ne valident pas activement les données soumises, supposant de manière optimiste que les données sont correctes. En cas d'erreur dans les données soumises, les nœuds de validation L2 lanceront activement une contestation.

Par conséquent, l'OPR implique une hypothèse de confiance : à tout moment, il existe au moins un nœud valideur L2 honnête. D'autre part, les contrats ZKR valident activement et à peu de frais les données soumises par le séquenceur au moyen de calculs cryptographiques.

(Méthode d'exploitation optimiste du rollup)

(Méthode d'opération ZK Rollup)

Cet article présente de manière approfondie le projet phare du rollup optimiste-Arbitrum One, en couvrant tous les aspects de l'ensemble du système. Après l'avoir lu attentivement, vous aurez une compréhension approfondie d'Arbitrum et du Rollup Optimiste/OPR.

Composants principaux et flux de travail d'Arbitrum

Contrats de base :

Les contrats les plus importants dans Arbitrum comprennent SequencerInbox, DelayedInbox, L1 Gateways, L2 Gateways, Outbox, RollupCore, Bridge, etc. Ils seront détaillés dans les sections suivantes.

Séquenceur :

Le séquenceur reçoit les transactions des utilisateurs, les trie, calcule les résultats des transactions et renvoie rapidement (généralement <1s) les reçus aux utilisateurs. Les utilisateurs voient souvent leurs transactions sur L2 en quelques secondes, ce qui offre une expérience similaire aux plateformes Web2.

Simultanément, le séquenceur diffuse immédiatement le dernier bloc L2 généré sous Ethereum hors chaîne. Tout nœud de couche 2 peut recevoir ces blocs L2 de manière asynchrone. Toutefois, ces blocs L2 ne sont pas définitifs à ce stade et peuvent être annulés par le séquenceur.

Toutes les quelques minutes, le séquenceur compresse les données de transaction L2 triées, les regroupe en lots et les soumet au contrat SequencerInbox de la couche 1 afin de garantir la disponibilité des données et le fonctionnement du protocole Rollup. En général, les données L2 soumises à la couche 1 ne peuvent pas être annulées et peuvent avoir un déterminisme final.

Nous pouvons résumer le processus ci-dessus : La couche 2 possède son propre réseau de nœuds, mais le nombre de ces nœuds est faible et il n'existe généralement pas de protocole de consensus communément utilisé par les chaînes publiques, de sorte qu'elle offre une sécurité très médiocre. Il doit s'appuyer sur Ethereum pour garantir la fiabilité de la diffusion des données et l'efficacité des transitions d'état. sexe.

Protocole de reconduction arbitrale :

Il s'agit d'une série de contrats qui définissent la structure du bloc RBlock de la chaîne Rollup, la méthode de continuation de la chaîne, la libération du bloc RBlock et le processus du mode défi. Notez que la chaîne Rollup mentionnée ici n'est pas le grand livre de niveau 2 que tout le monde connaît, mais une "structure de données de type chaîne" abstraite mise en place indépendamment par Arbitrum One afin de mettre en œuvre le mécanisme de preuve de fraude.

Un bloc R peut contenir les résultats de plusieurs blocs L2, et les données sont également très différentes. Son entité de données RBlock est stockée dans une série de contrats dans le RollupCore. En cas de problème avec un RBlock, le validateur interpellera l'auteur du RBlock.

Valideur :

Les nœuds validateurs d'Arbitrum sont en fait un sous-ensemble spécial de nœuds complets de la couche 2, et ont actuellement accès à une liste blanche.


Le validateur crée un nouveau bloc R (bloc de rollup, également appelé assertion) sur la base du lot de transactions soumis par le séquenceur au contrat SequencerInbox. Il surveille également l'état de la chaîne de rollup en cours et conteste les données incorrectes soumises par le séquenceur.

Le validateur actif doit mettre en jeu des actifs sur la chaîne ETH à l'avance. Parfois, nous l'appelons aussi Staker. Bien que les nœuds de la couche 2 qui n'interviennent pas puissent également surveiller la dynamique de fonctionnement du Rollup et envoyer des alarmes anormales aux utilisateurs, ils ne peuvent pas intervenir directement sur les données d'erreur soumises par le séquenceur de la chaîne de l'EPF.

Défi :

Les étapes de base peuvent être résumées en plusieurs tours de segmentation interactive et une preuve en une seule étape. Dans le cadre du processus de segmentation, les parties en cause effectuent d'abord plusieurs cycles de segmentation sur les données de transaction problématiques jusqu'à ce qu'elles décomposent les instructions de code d'opération problématiques et procèdent à une vérification. Les développeurs d'Arbitrum considèrent que le paradigme "plusieurs tours de segmentation - une preuve en une étape" est la mise en œuvre la plus économe en gaz de la preuve de fraude. Tous les liens sont soumis à un contrôle contractuel et aucune partie ne peut tricher.

Période de défi :

En raison de la nature optimiste de l'OP Rollup, après que chaque RBlock a été soumis à la chaîne, le contrat ne procède pas à une vérification active, ce qui laisse au vérificateur une période de latence pour falsifier. Cette fenêtre correspond à la période de défi, qui dure une semaine sur le réseau principal d'Arbitrum One. À l'issue de la période de défi, le RBlock sera définitivement confirmé. Seuls les messages correspondants transmis de L2 à L1 au sein du bloc (tels que les opérations de retrait effectuées par le biais du pont officiel) peuvent être libérés.

ArbOS, Geth, WAVM:

La machine virtuelle utilisée par Arbitrum est appelée AVM, qui comprend Geth et ArbOS. Geth est le logiciel client le plus couramment utilisé dans Ethereum, et Arbitrum y a apporté des modifications légères. ArbOS est responsable de toutes les fonctions spéciales liées à la L2, telles que la gestion des ressources du réseau, la génération de blocs L2, la collaboration avec EVM, etc. Nous considérons la combinaison des deux comme un AVM natif, qui est la machine virtuelle utilisée par Arbitrum. WAVM est le résultat de la compilation du code AVM dans Wasm. Dans le processus de contestation Arbitrum, la dernière "preuve en une étape" vérifie l'instruction WAVM.

Nous pouvons utiliser la figure suivante pour représenter la relation et le flux de travail entre les composants ci-dessus :

Cycle de vie des transactions sur L2

Le flux de traitement d'une transaction sur L2 est le suivant :

  1. Les utilisateurs envoient des instructions commerciales au séquenceur.

  2. Le séquenceur vérifie d'abord les transactions à traiter en signatures numériques et autres données, élimine les transactions non valides et effectue des séquences et des calculs.

  3. Le séquenceur envoie le reçu de la transaction à l'utilisateur (généralement très rapidement), qui n'est que le "prétraitement" effectué par le trieur dans le cadre de la chaîne de l'EPF. Il se trouve à l'état de finalité molle et n'est pas fiable. Mais pour les utilisateurs (la plupart des utilisateurs) qui font confiance au séquenceur, ils peuvent être optimistes et penser que la transaction a été effectuée et qu'elle ne sera pas annulée.

  4. Le séquenceur compresse fortement les données de transaction originales prétraitées et les encapsule dans un lot.

  5. De temps en temps (en fonction de facteurs tels que le volume de données et la congestion de l'ETH), le séquenceur publiera des lots de transactions dans le contrat Sequencer Inbox sur L1. À ce stade, on peut considérer que la transaction a atteint le stade de la finalité absolue.

Contrat de boîte de réception du séquenceur

Le contrat recevra le lot de transactions soumis par le séquenceur afin de garantir la disponibilité des données. Si nous regardons cela de plus près, les données de lot dans la boîte de réception du séquenceur enregistrent complètement les informations d'entrée de la transaction de la couche 2. Même si le séquenceur est définitivement hors service, n'importe qui peut rétablir l'état actuel de la couche 2 sur la base de l'enregistrement du lot et remplacer le séquenceur défectueux ou en cours d'exécution.

Pour comprendre cela d'une manière physique, la L2 que nous voyons n'est que la projection du lot dans SequencerInbox, et la source de lumière est STF. Comme la source lumineuse STF ne change pas facilement, la forme de l'ombre n'est déterminée que par le lot agissant comme l'objet.

Le contrat de boîte de réception du séquenceur est appelé boîte rapide. Le séquenceur lui soumet spécifiquement des transactions prétraitées, et seul le séquenceur peut lui soumettre des données. La boîte rapide correspondante est la boîte lente Delayer Inbox, dont la fonction sera décrite dans le processus suivant.

Le validateur surveillera toujours le contrat de la boîte de réception du séquenceur. Chaque fois que le séquenceur libère un lot dans le contrat, un événement sur la chaîne est produit. Une fois que le validateur a détecté l'occurrence de cet événement, il télécharge les données du lot. Après l'exécution locale, le RBlock sera délivré au contrat du protocole Rollup sur la chaîne ETH.

Le contrat de bridge d'Arbitrum a un paramètre appelé accumulateur, qui enregistre le lot L2 nouvellement soumis, ainsi que le nombre et l'information des transactions nouvellement reçues sur la boîte de réception lente.


(Le séquenceur soumet continuellement des lots à la boîte de réception du séquenceur)

(Les informations spécifiques du lot ; le champ de données correspond aux données du lot. La taille de cette partie des données est très importante et la capture d'écran n'est pas entièrement affichée.)

Le contrat SequencerInbox a deux fonctions principales :

ajouter le séquenceur L2Batch From Origin()

Le séquenceur appellera cette fonction à chaque fois qu'il soumettra des données de lot au contrat Inox du séquenceur.

force Inclusion()

Cette fonction peut être appelée par n'importe qui et est utilisée pour mettre en œuvre des transactions résistantes à la censure. La manière dont cette fonction prend effet sera expliquée en détail plus loin, lorsque nous parlerons du contrat de boîte de réception différée.

Les deux fonctions ci-dessus appellent "bridge.enqueueSequencerMessage()" pour mettre à jour le paramètre "accumulator" dans le contrat "bridge".

Prix du gaz

Il est évident que les transactions L2 ne peuvent pas être gratuites, car cela entraînerait des attaques DoS. En outre, il y a des coûts d'exploitation pour la trieuse L2 elle-même, et il y aura des frais généraux pour la transmission des données sur L1. Lorsqu'un utilisateur effectue une transaction au sein du réseau de niveau 2, la structure de la redevance gazière est la suivante :

Coûts de publication des données liés à l'occupation des ressources de la couche 1

Ce coût provient principalement des lots soumis par le séquenceur (chaque lot contient de nombreuses transactions d'utilisateurs), et le coût est finalement réparti de manière égale entre les initiateurs de transactions. L'algorithme de tarification des frais généré par la libération des données est dynamique, et le séquenceur fixera le prix en fonction de l'état récent des profits et des pertes, de la taille du lot et du prix actuel du gaz Ethereum.

Coût supporté par les utilisateurs qui occupent les ressources de la couche 2

Une limite de gaz pour le TPS est établie pour assurer le fonctionnement stable du système (actuellement 7 millions dans Arbitrum One). Les prix d'orientation du gaz pour L1 et L2 sont suivis et ajustés par ArbOS, et la formule n'est pas détaillée ici pour l'instant.

Bien que le processus de calcul du prix du gaz soit relativement compliqué, les utilisateurs n'ont pas besoin de connaître ces détails et peuvent clairement sentir que les frais de transaction de Rollup sont beaucoup moins élevés que ceux du mainnet ETH.

Preuve de fraude optimiste

Si l'on se souvient de ce qui précède, L2 n'est en fait que la projection du lot d'entrée de transaction soumis par le séquenceur dans la boîte rapide, c'est-à-dire

Transaction Inputs -> STF -> State Outputs. L'entrée a été déterminée et le STF est inchangé, de sorte que le résultat de la sortie est également déterminé. Le système de preuve de fraude et le protocole Arbitrum Rollup sont des systèmes qui publient la racine de l'état de sortie sous la forme d'un RBlock (alias assertion) à L1 et qui effectuent une preuve optimiste sur cette racine.

Sur L1, il y a des données d'entrée publiées par le séquenceur et un état de sortie publié par le vérificateur. Examinons-le attentivement : Est-il nécessaire de publier l'état de la couche 2 à la chaîne ?

Étant donné que l'entrée a entièrement déterminé la sortie et que les données d'entrée sont publiquement visibles, ne semble-t-il pas redondant de soumettre l'état-résultat de la sortie ? Mais cette idée ne tient pas compte du besoin réel de règlement de l'état entre les deux systèmes L1 et L2, c'est-à-dire que le comportement de retrait de L2 vers L1 nécessite une preuve de l'état.

Lors de la création de Rollup, l'une des idées maîtresses est de placer la majeure partie du calcul et du stockage sur L2 afin d'éviter le coût élevé de L1. Cela signifie que L1 ne connaît pas le statut de L2, il ne fait qu'aider L2. Le séquenceur publie les données d'entrée de toutes les transactions, mais n'est pas responsable du calcul de l'état de L2.

Le comportement de retrait consiste essentiellement à débloquer les fonds correspondants du contrat L1, à les transférer sur le compte L1 de l'utilisateur ou à effectuer d'autres opérations en suivant le message inter-chaîne donné par L2.

À ce moment-là, le contrat de la couche 1 demandera : quel est votre statut à la couche 2 et comment prouver que vous possédez réellement les actifs que vous déclarez être transférés ? L'utilisateur doit alors fournir la preuve de Merkle correspondante, etc.

Par conséquent, si nous construisons un rollup sans fonction de retrait, il est théoriquement possible de ne pas synchroniser l'état avec L1, et il n'est pas nécessaire de mettre en place un système de preuve d'état tel que la preuve de fraude (bien que cela puisse poser d'autres problèmes). Mais dans les applications réelles, cela n'est évidemment pas possible.

Dans la preuve dite optimiste, le contrat ne vérifie pas si l'état de sortie soumis à L1 est correct, mais croit de manière optimiste que tout est exact. Le système de preuve optimiste suppose qu'il existe au moins un validateur honnête à tout moment. Si un état incorrect se produit, il sera contesté au moyen d'une preuve de fraude.

L'avantage de cette conception est qu'il n'est pas nécessaire de vérifier activement chaque RBlock émis vers L1 pour éviter de gaspiller du gaz. En fait, pour OPR, il n'est pas réaliste de vérifier chaque assertion, car chaque bloc R contient un ou plusieurs blocs L2, et chaque transaction doit être réexécutée sur L1. Ce n'est pas différent de l'exécution des transactions L2 directement sur L1, ce qui rend l'expansion de la couche 2 inutile.

ZKR n'a pas ce problème, car ZK Proof est concis. Il ne doit vérifier qu'une très petite preuve, et il n'est pas nécessaire d'exécuter de nombreuses transactions correspondant à la preuve. Par conséquent, ZKR ne fonctionne pas de manière optimiste. Chaque fois que le statut est publié, il y aura un contrat Verifier pour la vérification mathématique.

Bien que la preuve de la fraude ne puisse pas être aussi concise que la preuve de l'absence de connaissance, Arbitrum utilise un processus interactif à tour de rôle "plusieurs tours de segmentation - une preuve en une étape". En fin de compte, ce qui doit être prouvé n'est qu'un seul code d'opération de machine virtuelle, et le coût est relativement faible.

Protocole d'enroulement

Examinons tout d'abord l'entrée pour lancer des défis et commencer des preuves, c'est-à-dire le fonctionnement du protocole Rollup.

Le contrat principal du protocole Rollup est RollupProxy.sol, qui utilise une structure rare d'agents doubles tout en garantissant la cohérence de la structure des données. Un agent correspond à deux implémentations de RollupUserLogic.sol et RollupAdminLogic.sol, qui ne peuvent pas être bien analysées par des outils tels que Scan.

En outre, le contrat ChallengeManager.sol est responsable de la gestion des défis, et les contrats de la série OneStepProver sont utilisés pour déterminer les preuves de fraude.

(Source : site officiel de L2BEAT)

Ceci montre l'enregistrement d'une série de RBlocks (aka assertions), dans RollupProxy, soumis par différents Validateurs, qui sont les cases dans la figure ci-dessous : Vert-confirmé, bleu-non-confirmé, jaune-falsifié.

RBlock contient l'état final après l'exécution d'un ou plusieurs blocs L2 depuis le dernier RBlock. Ces RBlocks forment une chaîne de rollup formelle (notez que le grand livre L2 lui-même est différent). Dans des conditions optimales, cette chaîne de rollup ne doit pas comporter de fourches, car une fourche signifie qu'un validateur a soumis des blocs de rollup contradictoires.

Pour proposer ou accepter une assertion, le vérificateur doit d'abord miser un certain montant d'ETH pour l'assertion et devenir un Staker. Ainsi, en cas de contestation/preuve de fraude, la garantie du perdant sera réduite. C'est la base économique pour garantir le comportement honnête du vérificateur.

Le bloc bleu n° 111 dans le coin inférieur droit de l'image sera finalement coupé parce que son bloc parent n° 104 (jaune) est erroné.

En outre, le vérificateur A a proposé le bloc de rollup n° 106, mais B n'était pas d'accord et l'a contesté.

Après que B a lancé la contestation, le contrat ChallengeManager est chargé de vérifier la segmentation des étapes de la contestation :

  1. La segmentation est un processus dans lequel les deux parties interagissent à tour de rôle. Une partie segmente les données historiques contenues dans un certain bloc de données, et l'autre partie indique quelle partie du fragment de données pose problème, un processus similaire à la dichotomie (en fait N/K) qui réduit continuellement et progressivement le champ d'application.

  2. Ensuite, vous pouvez continuer à localiser la transaction et le résultat qui posent problème, puis les subdiviser en une instruction machine contestée dans la transaction.

  3. Le contrat ChallengeManager vérifie uniquement si les "fragments de données" générés après avoir segmenté les données originales sont valides.

  4. Lorsque le contestataire et la partie contestée localisent l'instruction machine qui sera contestée, le contestataire appelle la fonction "oneStepProveExecution()" et envoie une preuve de fraude en une étape pour prouver qu'il y a un problème avec le résultat de l'exécution de cette instruction machine.

Preuve en une étape

La preuve en une étape est au cœur de l'ensemble de la preuve de la fraude Arbitrum. Voyons ce que la preuve en une étape prouve spécifiquement.

Pour cela, il faut d'abord comprendre le WAVM. Wasm Arbitrum Virtual Machine est une machine virtuelle compilée par le module ArbOS et le module central Geth (client Ethereum). La L2 étant très différente de la L1, le noyau Geth original a dû être légèrement modifié et fonctionner avec ArbOS.

Par conséquent, la transition d'état sur L2 est en fait le fruit du travail conjoint d'ArbOS+Geth Core.

Le client de nœud d'Arbitrum (séquenceur, vérificateur, nœud complet, etc.) compile le programme de traitement ArbOS+Geth Core mentionné ci-dessus en code machine natif que l'hôte du nœud peut traiter directement (pour x86/ARM/PC/Mac/etc.).

Si vous changez le langage cible obtenu après la compilation en Wasm, vous obtiendrez le WAVM utilisé par le vérificateur lors de la génération des preuves de fraude, et le contrat de vérification de la preuve en une étape simule également les fonctions de la machine virtuelle WAVM.

Alors pourquoi doit-il être compilé en bytecode Wasm lors de la génération de preuves de fraude ? La raison principale est que, pour vérifier le contrat de preuve de fraude en une étape, il est nécessaire d'utiliser le contrat intelligent Ethereum pour simuler une machine virtuelle VM qui peut gérer un certain ensemble d'instructions, et WASM est facile à mettre en œuvre la simulation sur le contrat.

Cependant, WASM est légèrement plus lent que le code machine natif, c'est pourquoi les nœuds/contrats d'Arbitrum n'utiliseront WAVM que pour générer et vérifier les preuves de fraude.

Après les précédentes séries de segmentations interactives, la preuve en une étape a finalement prouvé l'instruction en une étape dans le jeu d'instructions WAVM.

Comme le montre le code ci-dessous, OneStepProofEntry détermine d'abord à quelle catégorie appartient le code d'opération de l'instruction à prouver, puis appelle le prouveur correspondant (Mem, Math, etc.) pour faire passer l'instruction en une étape dans le contrat du prouveur.

Le résultat final afterHash sera renvoyé au ChallengeManager. Si le hachage n'est pas cohérent avec le hachage obtenu après l'opération d'instruction enregistrée sur le bloc de rollup, la contestation est réussie. S'ils sont cohérents, cela signifie qu'il n'y a pas de problème avec le résultat de l'exécution de cette instruction enregistré sur le bloc de rollup, et que la contestation a échoué.

Dans la deuxième partie, nous analyserons Arbitrum et même le module de contrat qui gère les fonctions de messagerie et de pont entre la couche 2 et la couche 1, et nous préciserons comment une véritable couche 2 devrait parvenir à résister à la censure.

Clause de non-responsabilité:

  1. Cet article est reproduit de[WeChat]. Tous les droits d'auteur appartiennent à l'auteur original[Luo Benben]. Si vous avez des objections à cette réimpression, veuillez contacter l'équipe de Gate Learn, qui s'en chargera rapidement.
  2. Clause de non-responsabilité : Les points de vue et les opinions exprimés dans cet article sont uniquement ceux de l'auteur et ne constituent pas un conseil en investissement.
  3. Les traductions de l'article dans d'autres langues sont effectuées par l'équipe de Gate Learn. Sauf mention contraire, il est interdit de copier, distribuer ou plagier les articles traduits.
Comece agora
Inscreva-se e ganhe um cupom de
$100
!
Criar conta