Article éducatif. Toutes les affirmations sur la plateforme renvoient à la documentation officielle Polkadot ou aux dépôts publics cités. La section application décrit un prototype expérimental (CypherTux / ctuxhello.dot) et ne constitue pas un audit de sécurité.
Pourquoi cet article
Beaucoup de développeurs web connaissent déjà une stack familière : build local, hébergement cloud, DNS, login OAuth ou extension wallet. Polkadot Products reprend ce geste mental (tu builds un front, tu le publies, les utilisateurs l’ouvrent) mais remplace plusieurs briques centrales.
L’objectif ici n’est pas de vendre une vision : c’est d’expliquer ce que propose la plateforme, comment les briques s’emboîtent, et comment un Product concret (un dead-drop scellé, sealed dead-drop) compose ces mécanismes : avec des liens officiels à chaque étape.
Point d’entrée officiel : Apps | Polkadot Developer Docs.
Qu’est-ce qu’un Polkadot Product ?
D’après la documentation Apps :
Polkadot Products are what you build: third-party applications that run inside one of the Polkadot Apps. Products are sandboxed single-page apps (HTML / JS / CSS), addressed by .dot names […], registered on-chain through a decentralized name service, and they never see the user's private key. The bundle itself is published to a decentralized cloud storage provider and fetched by the Host on demand.
Source : docs.polkadot.com/apps.
En pratique :
- Tu livres un bundle front (SPA).
- Tu le publies via la capacité Cloud Storage du Host, qui s’appuie sur Bulletin (stockage content-adressé).
- Tu l’adresses avec un nom .dot via dotNS.
- L’utilisateur l’ouvre dans un Host (sandbox) , la clé privée reste hors du Product.
Tu ne déploies pas trois apps natives : un même Product peut être utilisé à travers les trois Hosts du Triangle (Mobile App, Desktop, Web), avec des capacités différentes selon le Host.
Le Triangle : où tourne l’app, où vit la clé
Les trois Hosts forment le Polkadot Triangle (glossaire) :
| Host | Rôle documenté |
|---|---|
| Polkadot App (mobile) | Porte la clé privée, approuve chaque signature |
| Polkadot Desktop | Charge les Products .dot en sandbox , ne détient pas la clé |
| Polkadot Web (dot.li) | Host navigateur , iframe sandbox , signature via App appairée |
Références :
Point structurel (répété dans la doc App) : Desktop et Web n’ont jamais la clé. L’appairage crée une session (clé publique de session) , chaque signature remonte sur le téléphone.
Pour un développeur web, l’analogie utile n’est pas « Metamask dans le navigateur », c’est plutôt : le runtime du Product est le Host , le coffre-fort de la clé privée reste le téléphone.
Trois identités, volontairement séparées
La page Identity distingue trois notions :
- Le nom .dot : nomme le Product en tant que ressource adressable (routage vers le CID du contenu), pas un utilisateur. Propriété on-chain (dotNS / Asset Hub), mais le nom ne signe pas.
- Le compte par app (product account) : dérivé pour cet utilisateur dans ce Product. Même personne sur app-a.dot et app-b.dot → adresses différentes par défaut (anti-corrélation).
- Proof of Personhood : tier (None / Lite / Full) + alias par app (Ring-VRF), pour « humain unique » sans exposer qui.
Le .dot nomme donc le Product côté adressage , ce même nom sert généralement de productId dans la dérivation du product account. Dérivation (doc Identity) : junctions product / productId / derivationIndex en soft sr25519. Formes d’adresse : SS58 et H160 (contrats pallet-revive sur Asset Hub).
SDK : SignerManager.getProductAccount : voir aussi Sign and Submit Transactions et Account Management (TrUAPI).
Où mettre les données : quatre mécanismes de placement
Guide de décision officiel : Where to Store Data.
| Mécanisme | Bon usage (doc) | Persistance | Taille |
|---|---|---|---|
| Contract storage | État / règles enforceables | Permanent | Petit, structuré |
| Cloud storage (via Bulletin) | Fichiers, blobs, posts | Limitée, renouvelable | Large |
| Statement Store | Signal temps réel | Secondes (éphémère) | Jusqu’à 512 octets |
| Local storage | Préférences, cache appareil | Jusqu’à clear | Petit |
Pattern recommandé dans la même page : le Statement Store annonce un changement , Bulletin porte le contenu (CID) , éventuellement un contrat référence le CID , le local storage accélère l’UI.
Erreur classique documentée : mettre du bulk dans un contrat. La doc dit explicitement de stocker les bytes sur Bulletin et de ne garder qu’un CID on-contract si besoin.
Bulletin Chain : fichiers = octets + CID
Rôle
La Bulletin Chain est l’infrastructure de stockage content-adressé des Products. Côté Product/Host, on parle souvent de capacité Cloud Storage , Bulletin en est le support sous-jacent (« decentralized cloud storage » dans la doc).
Références :
- Bulletin Chain Reference
- Data Storage (Hub)
- Store Data on Chain
- Repo : paritytech/polkadot-bulletin-chain
Tu soumets des octets , le système produit un CID qui identifie cryptographiquement le contenu. Dans le modèle documenté ici, l’empreinte sous-jacente est typiquement un Blake2b-256 et le CID est compatible avec les mécanismes IPFS. À contenu et encodage identiques, le CID reste identique. Pour lire le contenu, le client utilise ce CID pour le récupérer sur le réseau.
Ce qui est on-chain vs servi
La doc Bulletin (Products) décrit une séparation (schéma encore marqué provisional sur certains détails) :
- On-chain : records (CID, autorisations, expiration).
- Réseau collators / P2P : livraison des octets (Bitswap / chemins IPFS documentés).
Autrement dit : ce n’est pas « chaque fichier vit forever dans le state trie comme un solde ». C’est une parachain spécialisée stockage, avec engagement et gating on-chain, et distribution des bytes côté collators.
Endpoints TestNet cités dans Data Storage : RPC wss://paseo-bulletin-rpc.polkadot.io, gateway https://paseo-ipfs.polkadot.io : et avertissement : les gateways IPFS génériques (ipfs.io, etc.) ne sont pas fiables pour Bulletin.
Écriture bridée (authorization)
Bulletin n’utilise pas de balances de token natives pour payer le storage « à l’ethereum ». L’accès écriture passe par une authorization (quota de transactions et d’octets, avec expiration). Sources : Data Storage : Authorization, Bulletin Chain Reference.
Au niveau de Bulletin, l’écriture est contrôlée par des authorizations , côté Host/Product, ces droits sont exposés et consommés via des allowances de capacité. Sur TestNet, la doc indique un faucet / Console UI pour obtenir une authorization. Dans un Host, l’allocation passe souvent par une allowance Bulletin (le Product demande, le Host/App alloue selon disponibilité).
Rétention et renew
Doc : Bulletin Chain Renewal.
- Fenêtre par défaut : environ deux semaines.
- renew : prolonge l’expiration du même record , le CID ne change pas , ce n’est pas un re-upload.
- Coût documenté : consomme une transaction du quota d’authorization , les bytes ne sont pas recomptés comme un nouvel upload.
- Oubli de renew → plus de garantie de disponibilité , après éviction collators, il faut re-uploader les mêmes bytes (même CID possible, nouvelle tx).
La doc marque encore comme provisional certains paramètres exacts (grace period, batch renew). Le cycle conceptuel (TTL + renew) est présenté comme stable.
Côté design runtime / README du repo Bulletin, le modèle soft-cap (store) / hard-cap (renew) et un plafond global de storage « permanent » (renouvelé) sont décrits pour éviter qu’un renew généralisé fasse grossir le réseau sans borne : voir paritytech/polkadot-bulletin-chain.
Tailles (TestNet, doc Hub)
D’après Data Storage : Size Limits :
- ~8 MiB max par transaction
- ~64 MiB max fichier chunké (DAG-PB / UnixFS)
- rétention ~2 semaines
Les gros bundles (dont souvent un front déployé) sont chunkés , le CID racine (manifest) est ce que l’on publie / référence.
dotNS : le nom .dot pointe vers un CID, pas une IP
Références :
Points vérifiés dans la doc :
- Rôle analogue au DNS : nom humain → contenu.
- Différences : on-chain , résolution vers un CID (bundle Product), pas une IP , pricing lié à la Proof of Personhood pour limiter le farming de noms courts.
- Registre sur Asset Hub (contrats), pas sur People ni Bulletin.
- Flux Host typique : navigue vers myproduct.dot → namehash → lit contenthash sur Asset Hub → décode CID → fetch bytes (gateway IPFS et/ou Bulletin P2P) → vérifie les bytes contre le CID → charge en sandbox.
Conséquence pédagogique : republier une app, c’est souvent publier de nouveaux octets (nouveau CID) puis mettre à jour le contenthash du .dot. Renew Bulletin, lui, garde le même CID.
Statement Store : signaler, pas archiver
Référence : Statement Store.
Caractéristiques documentées :
- Messages courts, signés, gossip / pool locale des nœuds : pas stockés dans les blocs comme un historique permanent.
- TTL court , data-placement : jusqu’à 512 bytes, expiration en secondes.
- Delivery best-effort (pas de retry/ACK/ordre garantis au protocole).
- Composition documentée : si le contenu doit survivre, Bulletin pour les bytes, Statement Store pour annoncer un CID / un signal live (ex. pattern Chat de l’App).
C’est l’équivalent conceptuel d’un pub/sub éphémère, pas d’une base de données.
SDK et contrainte Host
Packages et recettes : Build, product-sdk (GitHub).
Exemples de packages documentés :
- @parity/product-sdk-signer : comptes + signature
- @parity/product-sdk-host : capacités Host (dont Preimage / allowances)
- @parity/product-sdk-cloud-storage : client Bulletin / Cloud Storage
- @parity/product-sdk-statement-store : pub/sub
Règle d’ingénierie Products : le Product tourne dans le Host et passe par l’API Host pour comptes, signature, storage. La doc cloud-storage insiste aussi sur le fait que certaines lectures CID sont container-only (pas de fallback gateway public dans le SDK) : voir skill / package cloud-storage et Store Data on Chain.
Dev local : Desktop peut charger localhost sans résolution .dot (Build : Set Up).
Déploiement : bundle → Bulletin + enregistrement nom via outils CLI / playground (voir docs Apps Quick Start / Deploy , playground CLI : paritytech/playground-cli).
Étude de cas : CypherTux (ctuxhello.dot)
Statut
Prototype / PoC éducatif, non audité, dérivé du template Playground. Stack observée dans le dépôt : React 19 + Vite + TypeScript, packages @parity/product-sdk-* (signer, host, cloud-storage, statement-store).
Déploiement de travail évoqué sur Products Devnet : nom ctuxhello.dot (gateway du type xxx.dev-dot.li selon l’environnement). Le branding cible cyphertux.dot n’est pas traité ici comme un fait de propriété on-chain vérifié dans cet article.
Intention produit
Un dead-drop scellé (sealed dead-drop) :
- L’utilisateur saisit un message et une passphrase.
- Le client chiffre en local (Web Crypto).
- Seule l’enveloppe scellée (JSON d’octets) est publiée sur Bulletin.
- Un board (index public des claims : CID + métadonnées non secrètes) liste les dépôts.
- Pour ouvrir : CID (ou lien) + même passphrase.
La confidentialité ne repose pas sur « le serveur cache le texte » : la lecture Bulletin est pensée ouverte à qui a le CID (Bulletin Reference : permissionless reads , privacy = chiffrer avant store). C’est exactement le modèle que l’app applique.
Crypto côté client (ce que fait le code)
Fichier src/cryptoDrop.ts (résumé factuel du repo) :
- PBKDF2-SHA-256 (120 000 itérations) à partir de la passphrase + salt
- AES-256-GCM
- Soft cap UX : 500 caractères de plaintext
- Enveloppe versionnée (champs v, s, n, c : salt / IV / ciphertext+tag en base64)
Avertissement du code lui-même : expérimental, non audité. Les métadonnées (CID, taille, signer d’upload, nom d’affichage public) restent visibles.
Composition des mécanismes Products (alignée avec la doc)
| Besoin | Mécanisme utilisé dans CypherTux | Alignement doc |
|---|---|---|
| Message scellé disponible pendant la durée de rétention Bulletin | Bulletin via Host getPreimageManager().submit | Store Data on Chain, data-placement |
| Board (index public des claims) | Index JSON aussi sur Bulletin (CID d’index) | Même logique « bytes sur Bulletin » |
| Annoncer la tête du board | Statement Store ChannelStore, canal board-head | Pattern « SS annonce, Bulletin porte » (Statement Store, data-placement) |
| Cache / labels locaux | localStorage | Local storage |
| Compte / login | Host + SignerManager / product account | Identity, Signer |
Détail d’implémentation important (repo) : l’upload Bulletin passe par PreimageManager Host (allowance Bulletin), pas par un CloudStorageClient.store branché sur un autre chemin de signature : commentaire explicite dans bulletinDrop.ts sur des échecs observés Desktop→Mobile avec CreateTransaction. C’est une contrainte d’intégration Host réelle, pas un détail cosmétique.
Liens de claim et résilience
L’UI construit des claim links du type ?cid=…&board=… :
- cid : enveloppe scellée
- board : CID d’index (optionnel) pour synchroniser le board sans dépendre uniquement du gossip Statement Store
Quand le Statement Store n’est pas « Live » (allowance manquante / sync dégradée), le Product peut encore fonctionner en partageant le claim link : cohérent avec le fait documenté que le Statement Store est best-effort et allowance-gated.
Ce que l’app n’est pas
- Pas un messenger chiffré de bout en bout type Signal (pas de modèle de clés utilisateur Host pour le decrypt dans ce PoC).
- Pas une preuve que « Bulletin = forever » : la rétention officielle reste ~2 semaines + renew.
- Pas un remplacement de GitHub : le code source reste hors chaîne , seule la publication du bundle / des blobs Products utilise Bulletin + dotNS.
Parallèle web classique (sans romancer)
- Build front → SPA dans le sandbox Host
- S3 / stockage d’assets → Bulletin (octets + CID)
- DNS / IP → dotNS / CID
- Extension wallet / OAuth → Host + App mobile (clé)
- Redis / presence → Statement Store
- localStorage → Local storage Host/appareil
La « puissance » argumentable à partir de la doc, sans inventer :
- Un bundle, trois Hosts (Triangle).
- Contenu vérifiable par hash (CID), pas confiance aveugle à « le serveur de l’auteur ».
- Compte par Product pour limiter la corrélation cross-app.
- Clé hors Product, signature sur Mobile.
- Placement de données explicite (contrat vs Bulletin vs SS vs local) au lieu d’un seul « backend ».
Les limites argumentables aussi à partir de la doc :
- Rétention Bulletin bornée + renew / quotas.
- Statement Store éphémère et best-effort.
- Écritures gated (authorizations / allowances).
- Lectures sensibles : chiffrer côté Product.
- Plateforme encore en mouvement (mentions provisional sur schémas Bulletin, paramètres exacts de renew, etc.).
Pour aller plus loin (parcours lecture)
Ordre suggéré :