IMA4 2018/2019 P22 : Différence entre versions
(→C. Génération des certificats cryptographiques et des clés privées) |
(→Rapport) |
||
(129 révisions intermédiaires par le même utilisateur non affichées) | |||
Ligne 426 : | Ligne 426 : | ||
Pour automatiser la manœuvre de déploiement et de test, j'ai préparé quelques scripts shell qui reprennent les étapes importantes du processus: | Pour automatiser la manœuvre de déploiement et de test, j'ai préparé quelques scripts shell qui reprennent les étapes importantes du processus: | ||
− | * mylauncher.sh | + | * Le script bash '''mylauncher.sh''' permet de: |
− | + | # préparer et initialiser notre réseau. | |
− | + | # deployer notre modèle. | |
− | + | # créer un utilisateur admin par défaut et se connecter avec ses identifiants. | |
− | + | # pinger le réseau | |
− | + | # générer un API-REST | |
+ | |||
+ | |||
* '''Lancement des conteneurs du réseau P22 IMA4 Prototype0...''' | * '''Lancement des conteneurs du réseau P22 IMA4 Prototype0...''' | ||
Ligne 468 : | Ligne 470 : | ||
===Résultat Prototype 0=== | ===Résultat Prototype 0=== | ||
− | [[Fichier: DemoPrototype0.mp4 |thumb|200px| VIDEO ]] | + | >>>'''[[Fichier: DemoPrototype0.mp4 |thumb|200px| VIDEO ]]''' |
+ | |||
Sur une machine virtuelle nous faisons le déploiement de notre réseau avec nos scripts. Nous créons donc un réseau avec: | Sur une machine virtuelle nous faisons le déploiement de notre réseau avec nos scripts. Nous créons donc un réseau avec: | ||
* Un Validateur (Orderer) | * Un Validateur (Orderer) | ||
Ligne 922 : | Ligne 925 : | ||
* ''crypto-config'': les certificats et les clés générés précédemment. | * ''crypto-config'': les certificats et les clés générés précédemment. | ||
* ''scripts'': les scripts qui vont nous permettre d'automatiser quelques tâches et qui seront présentés plus bas. | * ''scripts'': les scripts qui vont nous permettre d'automatiser quelques tâches et qui seront présentés plus bas. | ||
− | * ''p22ChannelArtefacts'': contient les artefacts pour | + | * ''p22ChannelArtefacts'': contient les artefacts pour le canal et les nœuds d'encrage générés précédemment. |
+ | |||
+ | |||
+ | * '''Lancement:''' | ||
+ | IMAGE_TAG=latest docker-compose -f docker-compose.yaml up -d | ||
+ | |||
+ | * '''Arrêt:''' | ||
+ | IMAGE_TAG=latest docker-compose -f docker-compose.yaml down -d | ||
+ | |||
+ | '''''Nota Bene:''''' parfois il est nécessaire d'effectuer le nettoyage des résidus des lancements précédents n'ayant pas été arrêtés correctement. | ||
+ | docker stop $(docker ps -a -q) | ||
+ | docker rm $(docker ps -a -q) | ||
+ | mais il faut savoir que ceci arrête tous les conteneurs en cours d’exécution sur docker. | ||
===Automatisation du déploiement du réseau=== | ===Automatisation du déploiement du réseau=== | ||
− | // | + | Maintenant que nous avons en main les différentes manœuvres pour lancer notre système, il est nécessaire d'automatiser ces étapes et d'ajouter des options utiles au processus pour de futures développements ou modifications. Comme annoncé précédemment nous n'utilisons qu'un seul ordonnanceur pour le moment et de ce fait dans notre fichier de configuration nous avons choisis ''ordererType:solo'' mais si nous avons le temps plus tard nous en configurerons plusieurs en utilisant le mode "Kafka". Il serait judicieux de prévoir ainsi un moyen de passer rapidement vers ce mode. Aussi pour sauvegarder l'état du réseau pour le moment et par défaut celui-ci est enregistré directement sur la mémoire des nœuds en entraînant de possible pertes (coupure électrique). Il sera par la suite utile de sauvegarder dans une base de donnée (couchedb). Le développement du chaincode est supporté au moment de l'écriture avec 3 langages "go", "nodeJs" et "Java" à condition de paramétrer environnement selon le choix. Ces options restent donc à étudier en plus de détails plus tard mais tout de même à prévoir. |
+ | |||
+ | Les grandes lignes du travail accompli est donc de: | ||
+ | # Permettre de regénérer si besoin les artefacts cryptographiques. | ||
+ | # Permettre de régénérer aussi le bloc de genèse, les configs de nœuds d'encrage ...etc | ||
+ | # Permettre de démarrer le réseau à partir de la configuration. | ||
+ | # Permettre d'ajouter les options. | ||
+ | # Se déplacer vers le conteneurs "cli" avec un "docker exec" afin d'exécuter les scripts de déploiement et d'installation de chaincode. | ||
+ | # Arrêter proprement le réseau. | ||
+ | # Nettoyer l'environnement. | ||
+ | |||
+ | Le script en question est le suivant >>> '''[https://github.com/Arezki1995/Blockchain/blob/3da6db57856876e6b46c63a112bccdb7fdc63d1f/p22NetworkArtefacts/MinistriesNet MinistriesNet]''' | ||
+ | |||
===Automatisation de l'installation et de l’instanciation du chaincode=== | ===Automatisation de l'installation et de l’instanciation du chaincode=== | ||
− | // | + | Souvenez-vous qu'en configurant les conteneurs nous avons monté un dossier "scripts" qui doit contenir les scripts dont il est question ici. En se basant sur les fonctions contenu dans cet [https://github.com/hyperledger/fabric-samples/blob/release-1.4/first-network/scripts/utils.sh exemple] nous mettons en place un script permettant d’utiliser ces fonctions afin d’exécuter certaines taches pour finaliser le lancement du réseau et l'installation automatique du chaincode sur les nœuds. |
+ | Ce fichier '''[https://github.com/Arezki1995/Blockchain/blob/1899fb640cff89cf08e80a2b386b8212dae785bd/p22NetworkArtefacts/scripts/utils.sh utils.sh]''' contient les fonctions suivantes | ||
+ | # verifyResult() | ||
+ | # setOrdererGlobals() | ||
+ | # setGlobals() | ||
+ | # updateAnchorPeers() | ||
+ | # joinChannelWithRetry() | ||
+ | # installChaincode() | ||
+ | # upgradeChaincode() | ||
+ | # chaincodeQuery() | ||
+ | # fetchChannelConfig() | ||
+ | # signConfigtxAsPeerOrg() | ||
+ | # createConfigUpdate() | ||
+ | # parsePeerConnectionParameters() | ||
+ | # chaincodeInvoke() | ||
+ | |||
+ | [[Que nous avons adaptées]] à notre réseau en modifiant les variables d'environnement et les chemins. | ||
+ | |||
+ | On peut utiliser ces dernières dans notre ''script.sh'' que nous allons créer en ajoutant cette instruction qui a la valeur d'un import en bash | ||
+ | . utils.sh | ||
+ | |||
+ | * '''[https://github.com/Arezki1995/Blockchain/blob/1899fb640cff89cf08e80a2b386b8212dae785bd/p22NetworkArtefacts/scripts/script.sh script.sh]''' | ||
+ | Les fonctions essentielles de ce script sont: | ||
+ | createChannel() { | ||
+ | #if TLS Off | ||
+ | ... | ||
+ | peer channel create -o orderer.p22network.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx >&log.txt | ||
+ | ... | ||
+ | #else | ||
+ | ... | ||
+ | peer channel create -o orderer.p22network.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA >&log.txt | ||
+ | ... | ||
+ | } | ||
+ | |||
+ | joinChannel () { | ||
+ | for min in 1 2; do | ||
+ | for peer in 0 1; do | ||
+ | joinChannelWithRetry $peer $min | ||
+ | ... | ||
+ | done | ||
+ | done | ||
+ | } | ||
+ | |||
+ | ... | ||
+ | updateAnchorPeers 0 1 | ||
+ | updateAnchorPeers 0 2 | ||
+ | ... | ||
+ | |||
+ | Ces dernières permettent d'appliquer les configurations des artefacts générés au réseau actuel (créer le canal en vrai) puis de faire en sorte que les nœuds rejoignent ce canal. Une fois ceci fait, appliquer les configurations pour les nœuds d'encrage. | ||
+ | |||
+ | Un autre point important: on doit spécifier la variable d’environnement '''CC_SRC_PATH''' indiquant le chemin vers les sources du chaincode et '''LANGUAGE''' le langage de développement utilisé. | ||
+ | |||
+ | Pour installer le chaincode sur un nœud donné: | ||
+ | installChaincode <peer_num> <Min_num> | ||
+ | Pour instancier le chaincode sur un nœud donné: | ||
+ | instantiateChaincode <peer_num> <Min_num> | ||
+ | |||
+ | Grâce aux paramètres <peer_num> <Min_num>, dans les fonctions adaptées plus haut, les bonnes variables d'environnement sont initialisées. Je vous invite à consulter le fichier utils.sh pour plus de détails. Mais sachez que nous reviendrons sur ce point de façon plus détaillée et explicite plus bas. | ||
===Test bout à bout du réseau=== | ===Test bout à bout du réseau=== | ||
− | // | + | >>>'''[[Fichier: Endtoend.mp4]]''' |
+ | |||
+ | En utilisant [https://github.com/hyperledger/fabric-samples/tree/release-1.4/chaincode/chaincode_example02/java un exemple de chaincode] et en lançant le script de déploiement avec les scripts discuté précédemment, nous retraçons toutes les phases décrites jusqu'ici. En suite, arrive la phase d' '''invocation''' du chaincode de test auquel nous '''soumettons des requêtes''' de calcul avec des arguments puis nous comparons les réponses avec les résultats attendus. Ceci est donc une confirmation que le réseau est bien fonctionnel. | ||
+ | |||
===Développement de la logique applicative=== | ===Développement de la logique applicative=== | ||
− | // | + | Nous parlerons ici des fonctionnalités qu'implémentera le chaincode que nous allons développer pour les noeuds. Dans le contexte de notre application de broadcast de messages. |
+ | Pour installation du chaincode nous avons mis en place un script spécifique dans le dossier scripts | ||
+ | arezki@blockchain:~/Blockchain/p22NetworkArtefacts$ tree scripts | ||
+ | scripts | ||
+ | ├── InstallMyCC.sh <--- Script d'installation | ||
+ | ├── addUser.sh | ||
+ | ├── broadcastMsg.sh | ||
+ | ├── broadcastSpam.sh | ||
+ | ├── broadcastUserNotExist.sh | ||
+ | ├── broadcastWrongPass.sh | ||
+ | ├── queryUser.sh | ||
+ | ├── queryUserMsgs.sh | ||
+ | ├── script.sh | ||
+ | ├── scriptWithTest.sh | ||
+ | └── utils.sh | ||
+ | |||
+ | ce script permet d'installer le chaincode sur tous les noeuds de notre réseau en modifiant les variables d'environnement à chaque fois. Ensuite, il l'initialise sur l'un des noeuds car il n'est necessaire d'initialiser qu'une fois sur un seul noeud. La documentation relative à l'installation se trouve [https://hyperledger-fabric.readthedocs.io/en/release-1.4/commands/peerchaincode.html ici.] | ||
+ | |||
+ | ====A. Choix du langage==== | ||
+ | Comme annoncé précedemment le développement peut se faire avec plusieurs languages, mais nous préférerons le faire en Java pour la familiarité avec ce dernier et son rapport avec les cours vu durant cette année. Nous utiliserons pour la gestion des dépendances l'outil Gradle car il est nécessaire pour que les noeud puissent faire le build au moment de l'installation du chaincode. | ||
+ | Notre répértoire de développement doit ressembler quelque chose de ce type là. | ||
+ | |||
+ | publicAnnouncement | ||
+ | ├── build.gradle | ||
+ | ├── settings.gradle | ||
+ | └── src | ||
+ | └── main | ||
+ | └── java | ||
+ | └── org | ||
+ | └── hyperledger | ||
+ | └── fabric | ||
+ | └── p22network | ||
+ | └── P22Chaincode.java | ||
+ | |||
+ | Pour la gestion des dépendences de ce projet: | ||
+ | |||
+ | *'''build.gradle''' | ||
+ | plugins { | ||
+ | id 'com.github.johnrengelman.shadow' version '2.0.3' | ||
+ | id 'java' | ||
+ | } | ||
+ | |||
+ | group 'org.hyperledger.fabric-chaincode-java' | ||
+ | version '1.0-SNAPSHOT' | ||
+ | |||
+ | sourceCompatibility = 1.8 | ||
+ | |||
+ | repositories { | ||
+ | mavenLocal() | ||
+ | mavenCentral() | ||
+ | } | ||
+ | |||
+ | dependencies { | ||
+ | compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.+' | ||
+ | compile group: 'org.json', name: 'json', version: '20180813' | ||
+ | } | ||
+ | |||
+ | shadowJar { | ||
+ | baseName = 'chaincode' | ||
+ | version = null | ||
+ | classifier = null | ||
+ | |||
+ | manifest { | ||
+ | attributes 'Main-Class': 'org.hyperledger.fabric.p22network.P22Chaincode' | ||
+ | } | ||
+ | } | ||
+ | |||
+ | Pour compiler: | ||
+ | arezki@blockchain:~/Blockchain/p22NetworkArtefacts/chaincode/publicAnnouncement$ gradle build | ||
+ | |||
+ | ====B. Java Chaincode API==== | ||
+ | Fabric Propose un [https://en.wikipedia.org/wiki/Shim_(computing) API Shim] pour gèrer l'interraction avec le chaincode.Tout code doit impérativiment implémenter l'interface '''chaincode''' dont les méthodes sont exécutées à la reception des propositions de transaction. Ces methodes sont: | ||
+ | * Invoke : pour soumettre des requêtes de transaction (Lecture/écriture sur le registre distribué). | ||
+ | * Init : fonction d'initialisation. ne se lance qu'une fois. | ||
+ | |||
+ | ====C. Stockage et structure de données==== | ||
+ | Pour plus de simplicité et afin d'aboutir plus rapidement à un prototype fonctionnel nous optons pour un stockage utilisant stateDB pour le maintien du registre distribué. Cette base de données se présente sous forme de couples <clé : valeur>. Le seul compromis que nous faisons contrairement à l'usage d'un autre système de stockage plus évolué tel que coucheDB est le fait de ne pas bénéficier des fonctionnalités de requêtes riches. Ceci n'est pas vraiment un problème car nous avons une solution, qui, dans le cadre de l'application que nous souhaitons réaliser, nous permettra de nous en affranchir: | ||
+ | Sur stateDB les possibilités offertes par l'API sont le stockage:<br> | ||
+ | <clé(String) : valeur (byte[])> : en utilisant putState().<br> | ||
+ | <clé(String) : valeur (String)> : en utilisant putStringState().<br> | ||
+ | La solution que nous proposons est d'utiliser la seconde combiné à la library org.json nous permettant d'utiliser des structures de données avancées (Objets JSON) et une particularité essentielle de sérialisation et de désérialisation en String pour faciliter le stockage. Vous avez sans doute remarqué qu'elle a été ajoutée à notre fichier de gestion des dépendances. | ||
+ | En ce qui est de la structure de données nous aurons un Id pour clé représentant l'Identifiant d'un utilisateur du système. La valeur, comme annoncé précédemment, sera un structure User représentée par ce squelette Json: | ||
+ | { | ||
+ | "Identity":{ | ||
+ | "NAME" : ....., | ||
+ | "ROLE" : ....., | ||
+ | "PWD" : ....., | ||
+ | "AFFIL": ....., | ||
+ | "CERT" : ..... | ||
+ | }, | ||
+ | "Messages":[ | ||
+ | {.......}, | ||
+ | {.......}, | ||
+ | ....... | ||
+ | ] | ||
+ | } | ||
+ | |||
+ | La clé '''Messages''' représentera un tableau qui contiendra des Objets de type '''Message''' représenté ci-dessous: | ||
+ | { | ||
+ | "ID" : ......, | ||
+ | "TIME" : ......, | ||
+ | "TITLE" : ......, | ||
+ | "CONTENT" : ...... | ||
+ | } | ||
+ | |||
+ | ====D. Fonctions Principales==== | ||
+ | package org.hyperledger.fabric.p22network; | ||
+ | import ... | ||
+ | public class P22Chaincode extends ChaincodeBase { | ||
+ | ... | ||
+ | @Override | ||
+ | public Response init(ChaincodeStub stub) { | ||
+ | ... | ||
+ | ... | ||
+ | } | ||
+ | @Override | ||
+ | public Response invoke(ChaincodeStub stub) { | ||
+ | try { | ||
+ | String func = stub.getFunction(); | ||
+ | List<String> params = stub.getParameters(); | ||
+ | if (func.equals("addUser")) { | ||
+ | return addUser(stub, params); | ||
+ | } | ||
+ | if (func.equals("delUser")) { | ||
+ | return delUser(stub, params); | ||
+ | } | ||
+ | if (func.equals("queryUser")) { | ||
+ | return queryUser(stub, params); | ||
+ | } | ||
+ | if (func.equals("broadcastMsg")) { | ||
+ | return broadcastMsg(stub, params); | ||
+ | } | ||
+ | return newErrorResponse("Invalid invoke function name. Expecting one of: [addUser, delUser, queryUser, broadcastMsg]"); | ||
+ | } catch (Throwable e) { | ||
+ | return newErrorResponse(e); | ||
+ | } | ||
+ | } | ||
+ | // create a chaincode user | ||
+ | private Response addUser(ChaincodeStub stub, List<String> args) { | ||
+ | ... | ||
+ | ... | ||
+ | } | ||
+ | // Deletes an entity from the world state | ||
+ | private Response delUser(ChaincodeStub stub, List<String> args) { | ||
+ | ... | ||
+ | ... | ||
+ | } | ||
+ | // Find a user entry in the storage | ||
+ | private Response queryUser(ChaincodeStub stub, List<String> args) { | ||
+ | ... | ||
+ | ... | ||
+ | } | ||
+ | // broadcast a Message | ||
+ | private Response broadcastMsg(ChaincodeStub stub, List<String> args) { | ||
+ | ... | ||
+ | ... | ||
+ | } | ||
+ | // MAIN | ||
+ | public static void main(String[] args) { | ||
+ | new P22Chaincode().start(args); | ||
+ | } | ||
+ | } | ||
+ | |||
===Tests de fonctionnement=== | ===Tests de fonctionnement=== | ||
− | // | + | A partir du conteneur '''cli''' nous pouvons, grâce au [https://hyperledger-fabric.readthedocs.io/en/release-1.4/commands/peerchaincode.html CLI API] de Fabric nous pouvons lancer des requêtes d'invocation depuis le terminal et ainsi tester le bon fonctionnement avec quelques scripts shell. |
− | ===Développement de l' | + | |
− | // | + | * '''addUser.sh''': ajouter un utilisateur client cette requête ne marche que si l'invocateur est administrateur |
+ | #!/bin/bash | ||
+ | # Expecting: Id, UserName, UserMinistry, UserPWD, adminID, adminPWD | ||
+ | peer chaincode invoke -o orderer.p22network.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n p22CC -c '{"Args":["addUser","001","user1","Min1","passwdofuser1","000","passwdofarezki"]}' | ||
+ | |||
+ | resultat: | ||
+ | ... | ||
+ | ... | ||
+ | 2019-05-05 21:25:37.128 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 04f Chaincode invoke successful. result: status:200 message:"User added Successfully:\n" payload:"{\"Messages\":[],\"Identity\":{\"ROLE\":\"Client\",\"AFFIL\":\"Min1\",\"CERT\":\"null\",\"PWD\":\"passwdofuser1\",\"NAME\":\"user1\"}}" | ||
+ | |||
+ | * '''broadcastMsg.sh''': poster un message | ||
+ | #!/bin/bash | ||
+ | # Expecting: UserId , userPWD, MsgTitle , MsgContent | ||
+ | peer chaincode invoke -o orderer.p22network.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n p22CC -c '{"Args":["broadcastMsg","001","passwdofuser1","Viva la vida","Lorem epsum in dolore"]}' | ||
+ | |||
+ | resultat: | ||
+ | ... | ||
+ | ... | ||
+ | 19-05-05 21:27:43.467 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 04f Chaincode invoke successful. result: status:200 message:"Message broadcasted Successfully:\n" payload:"{\"Messages\":[{\"TIME\":\"2019-05-09T21:27:43.407585253Z\",\"TITLE\":\"Viva la vida\",\"CONTENT\":\"Lorem epsum in dolore\",\"ID\":\"70b4817e6c43c8711711c89ed0981d7e35b3730e93e6c49ab4a177200eaa2c55\"}],\"Identity\":{\"ROLE\":\"Client\",\"AFFIL\":\"Min1\",\"CERT\":\"null\",\"PWD\":\"passwdofuser1\",\"NAME\":\"user1\"}}" | ||
+ | |||
+ | |||
+ | * '''broadcastMsgUserNotExist.sh''': poster un message avec un utilisateur non-existant | ||
+ | #!/bin/bash | ||
+ | # Expecting: UserId , userPWD, MsgTitle , MsgContent | ||
+ | peer chaincode invoke -o orderer.p22network.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n p22CC -c '{"Args":["broadcastMsg","9999","passwdofuser999","Viva la vida","Lorem epsum in dolore"]}' | ||
+ | |||
+ | resultat: | ||
+ | ... | ||
+ | ... | ||
+ | 2019-05-05 21:29:45.070 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> DEBU 04c ESCC invoke result: response:<status:500 message:"transaction returned with failure: \nError: USER WITH ID [9999] DOES NOT EXIST\n" > Error: endorsement failure during invoke. response: status:500 message:"transaction returned with failure: \nError: USER WITH ID [9999] DOES NOT EXIST\n" | ||
+ | |||
+ | * '''broadcastWrongPass.sh''': poster un message avec un mauvais mot de passe pour l' Id utilisateur fourni | ||
+ | #!/bin/bash | ||
+ | # Expecting: UserId , userPWD, MsgTitle , MsgContent | ||
+ | peer chaincode invoke -o orderer.p22network.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n p22CC -c '{"Args":["broadcastMsg","001","wrongpasswd","Hackeur du dimanche","Spending some time making examples for demo"]}' | ||
+ | |||
+ | resultat: | ||
+ | ... | ||
+ | ... | ||
+ | 2019-05-05 21:32:07.955 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> DEBU 04c ESCC invoke result: response:<status:500 message:"transaction returned with failure: \nError: WRONG PASSWORD. NO RIGHTS TO PUBLISH" > Error: endorsement failure during invoke. response: status:500 message:"transaction returned with failure: \nError: WRONG PASSWORD. NO RIGHTS TO PUBLISH" | ||
+ | ... | ||
+ | |||
+ | Les résultats des tests semblent concluants. | ||
+ | |||
+ | ===Développement de l'application client=== | ||
+ | |||
+ | Sur Fabric, l'application client est ce qui relie notre chaincode déployé sur le réseau au monde extérieur. Cette intéraction passe à travers le SDK qui est diponibles dans plusieurs languages (Java, NodeJs). Nous utiliserons cette fois le SDK Node pour deux principales raisons: | ||
+ | * Documentation plus importante qu'en Java. | ||
+ | * Facilité de créer un API rest moyennant des packages javaScript. | ||
+ | |||
+ | Les packetages NPM du SDK sont: | ||
+ | |||
+ | * fabric-client: fonctions nécessaires à l'instantiation, la soumission des requêtes et des transactions vers le réseau. | ||
+ | * fabric-ca-client: pour interragir avec les authorités de certification de Hyperledger Fabric. Gestion des enregistrement des clients et des rôles. | ||
+ | |||
+ | [https://github.com/hyperledger/fabric-sdk-node Lien vers les Packetages] | ||
+ | |||
+ | ====A. Configuration de l'accès==== | ||
+ | Il question dans cette partie d'expliquer comment un client pourra accèder à notre réseau et interragir avec lui. Avant de pouvoir faire celà un client doit déjà être '''enregistré''' pour avoir ces identifiants et ces certificats. Ce processus d'enregistrement est fait par un administrateur auprès d'une authorité de certification. | ||
+ | Mais avant de parler ça nous abordons une partie toute aussi importante. Les profils de connexion. | ||
+ | ===== a. Profils de connexion===== | ||
+ | Un profil de connexion est un moyen de conserver les informations necessaires sur l'infrastructure de notre réseau pour que nos clients puissent s'y connecter. Il contient entre autres les '''urls''' vers les différentes entités ainsi que les certificats cryptographiques necessaires. | ||
+ | |||
+ | arezki@blockchain:~/Blockchain/p22NetworkArtefacts/client$ cat connexion.json | ||
+ | { | ||
+ | "name": "p22network", | ||
+ | "x-commitTimeout": 300, | ||
+ | "version": "2.0.0", | ||
+ | "client": { | ||
+ | "organization": "Min1", | ||
+ | "connection": { | ||
+ | "timeout": { | ||
+ | "peer": { | ||
+ | "endorser": "300", | ||
+ | "eventHub": "300", | ||
+ | "eventReg": "300" | ||
+ | }, | ||
+ | "orderer": "300" | ||
+ | } | ||
+ | } | ||
+ | }, | ||
+ | "channels": { | ||
+ | "composerchannel": { | ||
+ | "orderers": ["orderer.p22network.com"], | ||
+ | "peers": { | ||
+ | "peer0.min1.p22network.com": {} | ||
+ | } | ||
+ | } | ||
+ | }, | ||
+ | "organizations": { | ||
+ | "Min1": { | ||
+ | "mspid": "Ministry1MSP", | ||
+ | "peers": ["peer0.min1.p22network.com"], | ||
+ | "certificateAuthorities": ["ca.min1.p22network.com"] | ||
+ | } | ||
+ | }, | ||
+ | "orderers": { | ||
+ | "orderer.p22network.com": { | ||
+ | "url": "grpc://localhost:7050", | ||
+ | "tlsCACerts": { | ||
+ | "pem": "-----BEGIN CERTIFICATE-----MIICTzCCAfagA... -----END CERTIFICATE-----" | ||
+ | } | ||
+ | } | ||
+ | }, | ||
+ | "peers": { | ||
+ | "peer0.min1.p22network.com": { | ||
+ | "url": "grpc://localhost:7051", | ||
+ | "tlsCACerts": { | ||
+ | "pem": "-----BEGIN CERTIFICATE-----MIICYzCCA... -----END CERTIFICATE-----" | ||
+ | } | ||
+ | } | ||
+ | }, | ||
+ | "certificateAuthorities": { | ||
+ | "ca.min1.p22network.com": { | ||
+ | "url": "https://localhost:7054", | ||
+ | "caName": "ca.min1.p22network.com" | ||
+ | }, | ||
+ | "tlsCACerts": { | ||
+ | "pem": "-----BEGIN CERTIFICATE-----MIICXTCCAgOgAwI.... -----END CERTIFICATE-----" | ||
+ | } | ||
+ | } | ||
+ | |||
+ | ===== b. Authorités de certification===== | ||
+ | Les autorités de certification servent à fournir, révoquer ou verifier des certificats. Pour avoir accès à ce service, il existe pour Fabric un conteneur spécial remplissant cette fonction '''fabric-ca'''.Etant donné que nous avons deux organisations (Ministères) il va donc falloir en créer deux. | ||
+ | Pour ce faire, nous apportons a notre fichier '''docker-compose.yaml les lignes suivantes: | ||
+ | services: | ||
+ | #adding a certificate authority for Min1 | ||
+ | ca.min1.p22network.com: | ||
+ | image: hyperledger/fabric-ca:latest | ||
+ | environment: | ||
+ | - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server | ||
+ | - FABRIC_CA_SERVER_CA_NAME=ca.min1.p22network.com | ||
+ | - FABRIC_CA_SERVER_TLS_ENABLED=true | ||
+ | - FABRIC_CA_SERVER_DEBUG=true | ||
+ | - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/3ee81323a141a0cfd7e5071b75621b1abbf648eb610fe37b17caeb8a88872cd0_sk | ||
+ | ports: | ||
+ | - "7054:7054" | ||
+ | command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.min1.p22network.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/3ee81323a141a0cfd7e5071b75621b1abbf648eb610fe37b17caeb8a88872cd0_sk -b arezki:pwdofarezki -d' | ||
+ | volumes: | ||
+ | - ./crypto-config/peerOrganizations/min1.p22network.com/ca/:/etc/hyperledger/fabric-ca-server-config | ||
+ | container_name: ca.min1.p22network.com | ||
+ | |||
+ | #adding a certificate authority for Min2 | ||
+ | ca.min2.p22network.com: | ||
+ | image: hyperledger/fabric-ca:latest | ||
+ | environment: | ||
+ | - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server | ||
+ | - FABRIC_CA_SERVER_CA_NAME=ca.min2.p22network.com | ||
+ | - FABRIC_CA_SERVER_TLS_ENABLED=true | ||
+ | - FABRIC_CA_SERVER_DEBUG=true | ||
+ | - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/0e7aa85027f1bdb5953b69e781f98e7084ec4178575af645464344b8532683aa_sk | ||
+ | ports: | ||
+ | - "8054:7054" | ||
+ | command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.min2.p22network.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/0e7aa85027f1bdb5953b69e781f98e7084ec4178575af645464344b8532683aa_sk -b arezki:pwdofarezki -d' | ||
+ | volumes: | ||
+ | - ./crypto-config/peerOrganizations/min2.p22network.com/ca/:/etc/hyperledger/fabric-ca-server-config | ||
+ | container_name: ca.min2.p22network.com | ||
+ | |||
+ | ===== c. Gestion des utilisateurs===== | ||
+ | ======[https://github.com/Arezki1995/Blockchain/tree/master/p22NetworkArtefacts/client adminEnrollment.js]====== | ||
+ | En utilisant le SDK sur NodeJs, nous enregistrons l'utilisateur administrateur auprès de l'autorité de certification. Une fois, fois que nous avons un administrateur nous pouvons enregistrer des clients. Le résultat de cette opération et la génération d'un couple Clé privée / clé publique et d'un certificat pour l'administrateur. | ||
+ | |||
+ | ======[https://github.com/Arezki1995/Blockchain/tree/master/p22NetworkArtefacts/client registerUser.js]====== | ||
+ | Nous montrons ici comment enregister un utilisateur "user1" auprès de l'autorité de certification. Le résultat de cette opération et la génération d'un couple Clé privée / clé publique et d'un certificat pour l'utilisateur "user1". | ||
+ | |||
+ | ======[https://github.com/Arezki1995/Blockchain/tree/master/p22NetworkArtefacts/client chaincodeInvoke.js] {problème}====== | ||
+ | Cette partie est supposée nous permettre d'invoquer notre chaincode et ainsi d'executer des transactions. Malheureusement, nous n'arrivons pas à determiner l'origine du problème empêchant la communication entre le script et le réseau malgré le fait qu'ils soient tous les deux en localhost. | ||
+ | |||
+ | ====B. API REST ==== | ||
+ | En raison, du problème percistant à l'invocation du chaincode avec chaincodeInvoke.js. Nous n'avons pas pu finir cette partie. Néanmoins, en voici les grandes lignes: | ||
+ | * Création des chemins: en utilisant les Packetages '''express''' et '''body-parser''' nous pouvons créer un serveur web allouer routes pour executer les fonctions d'invocation comme peut l'illustrer cet exemple: | ||
+ | |||
+ | const express = require('express') | ||
+ | const app = express() | ||
+ | var bodyParser = require('body-parser') | ||
+ | app.get('/api/msg', (req, res) => { | ||
+ | // ...queryMsg | ||
+ | }); | ||
+ | app.post('/api/msg', (req, res) => { | ||
+ | // ...broadcastMsg | ||
+ | }); | ||
+ | app.get('/api/users', (req, res) => { | ||
+ | // ...queryUser | ||
+ | }); | ||
+ | app.post('/api/users', (req, res) => { | ||
+ | // ... addUser | ||
+ | }); | ||
+ | app.delete('/api/users', (req, res) => { | ||
+ | // ...delUser | ||
+ | }); | ||
+ | app.listen(2020, () => | ||
+ | console.log(`Serveur en écoute sur port 2020!`), | ||
+ | ); | ||
+ | |||
+ | * Création d'une interface web simple: deux menus (Utilisateur/Admin) avec un champs de text pour remplir les arguments. | ||
+ | |||
===Test Finaux=== | ===Test Finaux=== | ||
− | // | + | //non lieu |
− | + | ||
− | |||
===Propositions d'amélioration=== | ===Propositions d'amélioration=== | ||
− | + | Durant cette première approche introductive, beaucoup de décisions ont été prises lors de la réalisation de façon à simplifier le travail. Ce qui offre des possibilités d'amélioration importantes: | |
+ | * Déverminer les fonctionnalités non-abouties. | ||
+ | * Implémenter l'interface web. | ||
+ | * Revoir l'architecture du réseau: ajouter notemment des ordonnanceurs pour décentraliser le travail (Kafka). | ||
+ | * Etoffer les fonctionnalités implémentées par le chaincode par des fonctions de recherches avancées. | ||
+ | * Utiliser la base de données CouchDB pour avoir accès à des fonctionnalités avancées. | ||
+ | * Explorer plus en profondeur la gestion de l'accès. | ||
+ | * Implémenter sur un vrai réseau et non en localhost. | ||
+ | |||
===Conclusion Générale=== | ===Conclusion Générale=== | ||
− | + | Les champs d’exploitation de la technologie blockchain sont immenses : banques, assurance, santé et industrie pharmaceutique, supply chain de nombreux secteurs (agroalimentaire, luxe, commerce international, distribution, vins, aéronautique, automobile…), industrie musicale, énergie, immobilier, vote… | |
+ | |||
+ | Surtout, la blockchain ouvre la voie d’un nouveau web, le web décentralisé, et d’une nouvelle économie numérique. Bien évidemment, ces promesses ne sont pas exemptes de défis, qu’ils soient économiques, juridiques, de gouvernance, ou encore écologiques. | ||
+ | |||
+ | Malgré que le projet n'a pas abouti à 100% à cause d'un soucis sur la phase finale de test. Il aura été d'un grand interêt car il a constitué une opportunité de travailler sur une technologie innovante et d'aborder beaucoup de sujets intéressants et d'actualité. | ||
==Feuille d'heures== | ==Feuille d'heures== | ||
Ligne 957 : | Ligne 1 412 : | ||
| 4 | | 4 | ||
| 4 | | 4 | ||
− | | | + | | |
− | | | + | | 5 |
− | | | + | | |
− | | | + | | 2 |
− | | | + | | 5 |
− | | | + | | 5 |
− | | | + | | |
|- | |- | ||
| Analyse du projet | | Analyse du projet | ||
Ligne 984 : | Ligne 1 439 : | ||
| | | | ||
| | | | ||
− | | | + | | |
− | | | + | | |
− | | | + | | |
− | | | + | | |
− | | | + | | |
− | | | + | | |
− | | | + | | |
− | | | + | | |
|- | |- | ||
| Prise en main des outils | | Prise en main des outils | ||
Ligne 997 : | Ligne 1 452 : | ||
| 4 | | 4 | ||
| 8 | | 8 | ||
− | | | + | | |
− | | | + | | |
− | | | + | | |
− | | | + | | |
− | | | + | | 2 |
− | | | + | | |
− | | | + | | |
− | | | + | | |
− | | | + | | |
|- | |- | ||
| Réalisation du prototype 0 | | Réalisation du prototype 0 | ||
Ligne 1 014 : | Ligne 1 469 : | ||
| 4 | | 4 | ||
| 4 | | 4 | ||
− | | | + | | |
− | | | + | | |
− | | | + | | |
− | | | + | | |
− | | | + | | |
− | | | + | | |
+ | |- | ||
+ | | Réalisation du prototype 1 | ||
+ | | | ||
+ | | | ||
+ | | | ||
+ | | | ||
+ | | | ||
+ | | | ||
+ | | 12 | ||
+ | | 20 | ||
+ | | 25 | ||
+ | | | ||
+ | | 24 | ||
+ | | | ||
|} | |} | ||
− | + | ||
+ | Ne sont pas comprises les journées entières des weeks ends et vacances. | ||
+ | <br> | ||
Modification de IMA4 2018_2019 P22 (section) — Wiki de Projets IMA | Modification de IMA4 2018_2019 P22 (section) — Wiki de Projets IMA | ||
==Prologue== | ==Prologue== | ||
=Documents Rendus= | =Documents Rendus= | ||
+ | Git: https://github.com/Arezki1995/Blockchain | ||
==Rapport== | ==Rapport== | ||
+ | [[Fichier:Rapport-aaitmouh.pdf]] | ||
==Références== | ==Références== | ||
− | https://media.readthedocs.org/pdf/hyperledger-fabric/release-1.4/hyperledger-fabric.pdf | + | Fonctionnement et concepts:<br> |
+ | https://media.readthedocs.org/pdf/hyperledger-fabric/release-1.4/hyperledger-fabric.pdf<br> | ||
+ | https://hyperledger-fabric.readthedocs.io/en/release-1.4/txflow.html <br> | ||
+ | https://hyperledger-fabric.readthedocs.io/en/release-1.4/arch-deep-dive.html <br> | ||
+ | https://hyperledger-fabric.readthedocs.io/en/release-1.4/functionalities.html <br> | ||
+ | https://hyperledger-fabric.readthedocs.io/en/release-1.4/smartcontract/smartcontract.html <br> | ||
+ | |||
+ | Les commandes:<br> | ||
+ | https://hyperledger-fabric.readthedocs.io/en/release-1.4/command_ref.html<br> | ||
+ | |||
+ | Exemples:<br> | ||
+ | https://github.com/hyperledger/fabric-samples/tree/release-1.4/basic-network<br> | ||
+ | https://github.com/hyperledger/fabric-samples/blob/release-1.4/first-network/byfn.sh<br> | ||
+ | https://fabric-ca.readthedocs.io/en/latest/users-guide.html<br> | ||
− | https://hyperledger-fabric.readthedocs.io/en/release-1.4/ | + | Divers:<br> |
+ | https://hyperledger-fabric.readthedocs.io/en/release-1.4/couchdb_as_state_database.html<br> | ||
+ | https://docs.oracle.com/javase/7/docs/api/java/security/cert/X509Certificate.html<br> | ||
+ | https://docs.oracle.com/javase/7/docs/api/java/security/cert/CertificateFactory.html<br> | ||
+ | https://stleary.github.io/JSON-java<br> | ||
− | https:// | + | Application Client<br> |
+ | https://fabric-sdk-node.github.io/release-1.4/index.html<br> | ||
==Glossaire== | ==Glossaire== | ||
https://hyperledger-fabric.readthedocs.io/en/release-1.2/glossary.html | https://hyperledger-fabric.readthedocs.io/en/release-1.2/glossary.html |
Version actuelle datée du 10 mai 2019 à 05:11
Sommaire
- 1 Présentation générale
- 2 Analyse du projet
- 3 Préparation du projet
- 4 Réalisation du Projet
- 4.1 Etat de l'art
- 4.2 Prise en main
- 4.3 Réalisation - Prototype 0
- 4.4 Réalisation - Prototype 1
- 4.4.1 Choix de la topologie du réseau
- 4.4.2 Automatisation du déploiement du réseau
- 4.4.3 Automatisation de l'installation et de l’instanciation du chaincode
- 4.4.4 Test bout à bout du réseau
- 4.4.5 Développement de la logique applicative
- 4.4.6 Tests de fonctionnement
- 4.4.7 Développement de l'application client
- 4.4.8 Test Finaux
- 4.4.9 Propositions d'amélioration
- 4.4.10 Conclusion Générale
- 4.5 Feuille d'heures
- 4.6 Prologue
- 5 Documents Rendus
Présentation générale
Dépôt Git
Afin de consulter le travail effectué sur ce projet un dépôt Git est disponible ici. Pour y accéder, vous devez au préalable disposer d'un compte sur la plateforme Git-hub et faire une demande d'accès à l'adresse: ait.mouheb.arezki@gmail.com
Présentation Générale
Introduction
Blockchain est une technologie de stockage et de transmission d’informations basé sur la cryptographie. Elle peut être vue comme une sorte de base de données distribuée, sécurisée et partagée. Autrement dit, c'est une structure de données qui contient des informations et qui n'est pas détenue par un serveur centralisé mais par toutes les machines connectées au réseau. Ces informations sont groupées en blocs d'une taille définie et chaque bloc est lié à celui qui le précède par un Hash Cryptographique créant ainsi une chaîne. Le véritable attrait de la Blockchain est de créer un registre de données qui est au même temps commun et extrêmement difficile à altérer.
Plusieurs implémentations de la technologie existent et beaucoup d'autres sont en cours de développement. Historiquement, la première et la plus connue reste la Cryptomonnaie Bitcoin qui est une variante spécifique dite publique c'est à dire que tous les utilisateurs ont les mêmes droits d'accès. Le potentiel d'application de la technologie a conduit à l'apparition d'autres variantes plus adaptées aux nouveaux usages.
On peut distinguer 2 autres types:
- Privée: propriété d'un individu ou organisation. Un nœud central décide d'octroyer les privilèges d'accès aux autres nœuds
- Fédérée ou Consortium: propriété d'un groupe. Les nœuds fédérateurs se réservent le droit de vérifier les blocs, voire de les créer.
Description du projet
L'idée de ce projet est d'explorer cette technologie par l'implémentation d'une variante fédérée de celle-ci qui sera illustrée par un système d'annonce public. Dans ce système, les membres du réseau peuvent se connecter et ainsi avoir accès aux messages diffusés mais seuls certains membres seront autorisés à émettre/valider une annonce. Les messages publiés seront protégés contre l'altération par les mécanismes de cryptage et de sécurité blockchain.
Objectifs
Ce projet est essentiellement un sujet d'exploration dont les objectifs principaux sont:
- Découvrir la Blockchain et analyser son potentiel technologique et économique.
- Découvrir les systèmes distribués pair à pair.
- Connaître les différents outils et plateformes de développement d'applications distribuées basés sur la Blockchain.
- Acquérir des compétences dans un domaine en pleine expansion.
- Implémenter une application mettant en œuvre cette technologie.
Analyse du projet
Positionnement par rapport à l'existant
La technologie blockchain est très récente et fait l'objet de beaucoup de projets de développement. Parmi ces derniers, certaines applications se rapprochent de l'objectif de ce projet c'est à dire la création d'un système de diffusion de contenu (annonce, messages). Parmi les plus aboutis, nous retrouvons deux projets majeurs.
Analyse du premier concurrent
Civil
Civil est une start-up qui propose un nouveau business modèle pour le journalisme. Ils proposent un système décentralisé de publication basé sur la Blockchain. Leur système permet à la communauté de voter pour élire les Newsrooms (groupes de journalistes représentant des nœuds dans le réseau) qui auront le droit de publier et de vérifier le contenu journalistique. Le droit de vote est acquis en disposant de Consumer Tokens, l'équivalent d'une monnaie client.
Spécificités:
- Plateforme de développement utilisée: Ethereum
- Système de diffusion à monnaie interne..
- Contenu partagé: Articles journalistiques, vidéos, podcasts ...
- Accès: Public.
Analyse du second concurrent
DNN:The Decentralised News Network
DNN "Decentralized News Network est une start-up qui utilise la technologie Blockchain pour la diffusion de l'information de façon vérifiable, transparente et protégée contre la censure en incitant les utilisateurs à contribuer à la validation et la vérification de contenu à travers un processus de revue rémunérant.
Spécificités:
- Plateforme de développement utilisée: Ethereum.
- Système de diffusion à monnaie interne: Ether.
- Contenu partagé: Articles journalistiques, podcasts ...
- Accès: Public.
Synthèse
Les concurrents analysés proposent des fonctionnalités très avancées de partage contenu et sont implémentés sur une plateforme (Ethereum) destinée à une architecture à accès public. Ce choix a ses avantages mais aussi des contraintes liées à l'utilisation obligatoire d'une monnaie locale incitant à la vérification des publications. Il faut savoir aussi que dans ce modèle toutes les diffusions sont publiques et donc consultables par toute personne ayant internet. Cette architecture utilise des protocoles de consensus pour résoudre les conflits qui sont efficaces mais impliquent des coûts calculatoires important. Enfin, le déploiement sur la plateforme Ethereum est orienté B2C et implique l'usage de la cryptomonnaie Ether.
A terme ce projet doit aboutir sur une architecture fédérée de validation avec des nœuds diffuseurs prédéfinis, sans avoir à utiliser de cryptomonnaie, exploitant des ressources libres pour le développement telles que Hyperledger de la Linux foundation qui sont plus flexibles tout en tirant profit des avantages d'une application décentralisée et sécurisée blockchain.
Scénario d'usage du concept
AGRI est un producteur agricole qui produit toutes sortes de fruits. Il les revend à BioF00d une entreprise qui crée à partir de ça plusieurs variétés de produits tels que des compotes, des confitures, des jus etc... qui sont ensuite acheminés par des camions vers des distributeurs partout en France puis vers les différents revendeurs. Les autorités sanitaires impose la traçabilité de toutes les denrées alimentaires pour connaître leurs origines et s'assurer que les normes sont respectées de la production au consommateur final. Les différents acteurs ont rencontré plusieurs problèmes avec les autorités car il y avait des incohérences dans les données que chaque entreprise gardait à différents points de passage. Aussi, ils ne cessent de se renvoyer la faute quant aux dégradations subit par les produits lors du transport. C'est là qu'ils entendent parler d'une startup "IoTchain" qui a développé un système très intéressant qui pourrait résoudre leur problème de traçabilité.
Le système est composé de deux parties:
- Un dispositif IoT qui mesure des données telles que la position, l’humidité, la température et bien d'autres grandeurs et les transmet sous forme de messages à un réseau Fédérateur pour les archiver dans une blockchain.
- Un réseau Fédérateur qui vérifie que seuls ces client IoT certifié (les dispositifs) peuvent écrire des données dans cette blockchain et offre aux autres clients l’opportunité de consulter seulement les données à travers une application web par exemple.
Avec ce système le consortium AGRI, BioF00d, Les entreprises de transport, les distributeurs, les revendeurs, les autorités sanitaires et même les clients peuvent avoir accès à ces informations et garantir l'intégrité de la donnée et une transparence totale sans qu'une entité ne les altère.
Réponse à la question difficile
Qu'est-ce qui fait la sécurité de la Blockchain?
Dans le domaine de l'informatique l'usage des fonctions de hachage cryptographiques telles que SHA256 est assez fréquent. Ce sont des fonctions qui, à une donnée de taille arbitraire, associent une image de taille fixe (digest ou hash). La propriété essentielle de ces fonctions est le fait qu'elles sont pratiquement impossibles à inverser. En d'autre termes, à partir d'un hash il s'avère très difficile de retrouver la donnée qui l'a produit. D'une autre part un petit changement dans la donnée d'entrée engendre un hash totalement différent.
Lorsque l'on insère un nouveau bloc dans une blockchain, on le relie au reste de la chaîne en y ajoutant un champ contenant le digest du bloc précédent. D'après ce qu'on a vu dans le paragraphe précédent, si l'on modifie un bloc (n), son digest ne sera plus le même donc le bloc suivant (n+1) n'aura plus un lien valide il faudra de ce fait le recalculer. En recalculant le lien dans le (n+1) nous changeons maintenant son contenu. Du coup, le bloc (n+2) n'aura plus un lien valide ...etc jusqu'au dernier bloc de la chaîne.
Ceci n'est pas suffisant pour garantir une sécurité car dans ce sens le calcul des Hash reste toujours faisable. C'est alors qu'intervient une autre composante importante qu'on appelle "protocole de consensus". Différents types de protocoles existent selon le type de système que l'on souhaite mettre en place.
Les protocoles de consensus
Nous n'allons pas détailler ici tous les protocoles existant mais nous allons nous intéresser à deux exemples bien précis. La preuve de travail PoW pour sa popularité étant donné son usage dans le réseau bitcoin et Practical Byzantine Fault Tolerance de par son usage dans le framework Hyperledger sur lequel nous allons baser notre travail.
1- Proof of work : (PoW)
C'est un protocole basé sur l'asymétrie du coût de calcul : le travail doit être difficilement réalisable, mais facilement vérifiable. Une implémentation de ce protocole peut être d'ajouter un champs dans le bloc "nonce" qui serait juste un chiffre dont le rôle est de faire varier le hash du bloc construit précédemment. D'une autre part on spécifie un critère pour le protocole par exemple :"Le hash après le calcul de la preuve de travail doit commencer par six '0' successifs." Comme les fonctions de hashage ne sont pas réversibles, la seule façon d y arriver est de calculer le Hash du bloc pour chaque valeur du "nonce" jusqu'à ce que le critère soit satisfait. Cette tache est très demandeuse en terme de puissance de calcul. Un fois que le critère est satisfait le bloc est validé par le protocol qui calcule le hash du bloc et le compare à la preuve de travail. S'il correspond, le bloc est ajouté à la chaîne. Pour comprendre le niveau de sécurité de cette solution, essayons de voir ce qu'il faut faire pour réussir à la contourner. Supposons qu'un nœud malveillant décide de modifier un bloc (n) pour quelque raison que ce soit. En faisant cela, il devra refaire la preuve de travail pour le bloc (n) puis recalculer le champ "Prev hash" dans le (n+1) puis sa preuve de travail et ainsi de suite pour le (n+2),(n+3)...etc ce qui s'avère être une tâche vorace en terme de puissance de calcul. Même s'il y arrive, il doit continuer à valider les nouveaux blocs (calculer la preuve de travail) pour maintenir la chaîne altérée qu'il vient de créer car le protocole est fait de telle sorte à considérer la chaîne la plus longue comme étant la chaîne de référence. Ceci donc nous amène à considérer les limites de cette solution:
- Si une entité malveillante possède 51% de la puissance de calcul du réseau elle pourra donc imposer sa version de la chaîne ce qui implique que le réseau doit être suffisamment grand pour que ça ne soit pas pratiquement possible qu'une entité puisse s'accaparer autant de puissance.
- Cet algorithme de consensus est vorace en énergie.
Conclusion: cet algorithme initial de consensus est certes très intéressant d'un point de vue sécurité sous resserve de certaines conditions mais ne correspond pas à tout type d'application.
2- Practical Byzantine Fault Tolerence : (PBFT)
"Byzantine Fault Tolerance" est l’habilité d'un système distribué basé sur le consensus à avoir assez d’éléments pour prendre une décision malgré la présence de nœuds malicieux ou défectueux en son sein. La problématique des généraux byzantins est à l'origine de cette réflexion mais le concept a été appliqué à beaucoup de systèmes critiques tels que les avions, les centrales nucléaires et les systèmes distribués modernes.
L'approche pratique (practical) prend en compte certaines suppositions:
- L’indépendance des nœuds en termes d'infection.
- La présence de messages altérés dans le système.
Dans ce système de validation, on tolère un nombre bien définit de nœuds malicieux (m) qui doit être inférieur au tiers du nombre de nœuds dans le réseau dans une fenêtre de vulnérabilité donnée (original paper). Dans ce cas, plus le réseau est grand, plus il devient sécurisé.
Dans ce système, les nœuds sont organisés de façon séquentielle avec un nœud Leader. Ils doivent communiquer entre eux de façon à décider du comportement du système en utilisant le principe de la majorité. A titre d'exemple, la validation, ou pas, d'un message.
La communication entre ces nœuds a deux buts:
- Prouver que le message est bien venu d'un nœud spécifique
- S'assurer que le message n'a pas été modifié durant la transmission.
Déroulement de l'algorithme:
- Un nœud envoie une requête au nœud Leader.
- Le Leader reçoit la requête puis la diffuse aux autres nœud réplica.
- Ces nœuds diffusent à leurs tours leurs réponses à la requête de façon à ce que chaque nœud sache ce que les autres ont répondu.
- Resultat:
- Si m+1 nœuds optent pour une même décision on est sûr qu'au moins un nœud "honnête" a répondu. Ainsi, la décision est Valide.
- Si unanimité le système est sein autrement le/les intrus est/sont détecté(s).
Le nœud Leader, est constamment vérifié. On s'assure de ça transparence grâce à la signature électronique de la requête. De plus, il est systématiquement remplacé par un autre nœud de façon séquentielle en cas d'inactivité constatée.
Les limites:
- L'algorithme suppose que le traitement des nœuds est déterministe. Pour la même requête les nœuds seins doivent donner le même résultat.
Framework Hyperledger-Fabric
Hyperledger Fabric est une plate-forme DLT (Distributed Ledger Technology) open source conçue pour être utilisée dans des contextes d'entreprise.
Un point clé de Hyperledger est le fait qu'elle a été créée sous la Linux Foundation, qui a elle-même une longue et fructueuse expérience de projets open source sous une gouvernance ouverte. Sa communauté de développeurs compte désormais plus de 35 organisations telles que IBM ou J.P Morgan et près de 200 développeurs depuis son lancement. Pour plus d'information consultez le site de la communauté ici.
Préparation du projet
Cahier des charges
- Prototype 0:
- Réalisation d'un premier système de diffusion d'annonce libre d’accès et sans protocole de consensus sur Hyperledger Fabric.
- Réalisation d'un API Rest sur javaScript simple pour interagir avec le système (GET,POST).
- Implémenter et déployer des clients simples visualisant les messages (Exemple: Page web).
- Prototype 1:
- Ajouter les mesures de sécurité et de vérification pour réserver le droit de diffusion aux Administrateurs et gérer l'accès au système.
- Un administrateur: peut lire et écrire.
- Un client : peut lire seulement
- Implémentation de clients qui devront interagir avec les messages diffusés (Exemples: Dispositif embarqué, Système d'alarme ...etc).
- Ajouter les mesures de sécurité et de vérification pour réserver le droit de diffusion aux Administrateurs et gérer l'accès au système.
Choix techniques : matériel et logiciel
Logiciel
Les spécificités du projet et l'étude initiale ont conduit au choix du framework Hyperledger pour la réalisation du prototype. Les outils de développement disponibles sur ce framework sont open-source et supportés par la Linux Foundation. Cette plateforme offre aussi un choix assez varié pour les langages de développement. Dans notre cas et affin de s'assurer d'un bonne compatibilité ainsi que pour bénéficier d'une documentation assez riche, nous optons pour une implémentation sur "node.js" en "javaScript".
Matériel
Le projet est essentiellement software donc le matériel requis initialement est:
- Une Raspberry Pi 3 avec Wifi inclus (ou Pi 2 avec le Dongle Wifi)
- Cable serie/USB
- Cable Ethernet RJ45
Liste des tâches à effectuer
Réalisation du Projet
Etat de l'art
Hyperledger Composer : Aspect applicatif simplifié
Ce framework propose une base intéressante pour la création d'applications blockchain. On distingue deux types d'outils distincts:
- Composer Playground: "terrain de jeu" c'est un outil graphique qui se présente sous forme d'une application web qui procure un environnement isolé de déploiement et de test pour des applications basiques à des fins d'apprentissage.
- Composer Developer Tools: une suite d'outils plus complète pour créer des applications plus poussées à des fin de production. Cette suite comprend:
- Hyperledger composer: ligne de commande pour créer et gérer les instances de la blockchain.
- Composer-rest-server: Un générateur d'API rest qui permet de créer à partir d'un modèle, qui sera expliqué plus bas, un API Rest squelette permettant d’interagir avec le réseau une fois déployé.
Quelques concepts importants
Hyperledger propose permet de modéliser les entités, la logique et les interactions au sein du domaine d'un réseau (Business Network). Cette modélisation se fait sous une structure bien définie comportant essentiellement:
Un fichier de modélisation (.cto)
HL propose un langage orienté objet permettant de définir:
- Un namespace : en français "espace de noms" définissant une notion de portée des objets qui seront déclarés dans ce fichier.
- Des définitions de ressources :
- Assets: une notion de Biens tangibles ou pas ou d'objets ayant une valeur quelconque.
- Participants: c'est les acteurs du réseau. Ils peuvent être des Individus ou des entités.
- Transactions: c'est un mécanisme qui permet aux acteurs du réseau d’interagir avec ces ressources.
- Events: Des événements peuvent être lancés lors de l’exécution de transaction pour prévenir un système externe (une application par exemple) que des changements importants ont été fait sur le registre partagé.
Fonctions de traitement des Transactions (.js)
Ces fonctions en JavaScript sont invoquées automatiquement à l'execution avec un système d'annotation pour implémenter la logique des transactions définies dans le modèle.
Un fichier de contrôle d’accès (.acl)
Ce fichier contient les règles d'accès et définit les actions autorisées ou non-autorisées sur le réseau en définissant le comportement de chacun de ses éléments.
Un fichier de requêtes (.qry)
Ce fichier comporte les requêtes dont la syntaxe se rapproche du SQL qui sont utilisées pour retourner des données sur l'état du réseau (les ressources, les transactions, ...). Ainsi, nous pouvons extraire de la données de la blockchain.
Développer des applications basées sur la technologie Blockchain utilisant Hyperleger introduit d'autres notions de niveau supérieur:
La sauvegarde de l'état
Toutes les transactions effectuées sur le réseau sont sauvegardé dans le registre distribué. L'état des "Biens" (Assets) et des Participants sont sauvegardés dans la base de donnée d'état de la blockchain. Les deux sont répartis sur tous les nœuds du réseau avec un mécanisme de consensus qui s'assure que tout les nœuds ont les mêmes données.
Les identités
Sur HL une identité est représentée par un certificat et et un clé cryptographique privée. Ces identités sont utilisées pour pouvoir effectuer des transactions sur le réseau. Une identité doit systématiquement être liée à un acteur du réseau (Participant). Pour une identité on peut créer un carte (Business Network card), qui, une fois liée à un acteur, lui permet d'agir sur le réseau en qualité de l'acteur en question.
Les Profils de connexion
Les profils de connexion sont utilisés dans Hyperledger composer pour spécifier comment se connecter à un environnement d'exécution. Plusieurs options sont disponibles pour chaque type d'environnement que nous verront plus bas. A titre d'exemple le profile de connexion sur l'environnement Hyperledger Fabric contient les adresses TCP/IP et les ports des nœuds du réseau et leurs certificats cryptographiques.
Ces Profils font partie des "Business Network Cards", évoquées plus haut, dont le rôle est de gèrer les accès au réseau de registres distribués.
Business Network cards
Un carte naît de la combinaison d'une identité, d'un profil de connexion et des informations supplémentaires concernant le réseau auquel on souhaite se connecter. Ces cartes simplifient seulement le mécanisme de connexion au réseau en regroupant les informations nécessaires en un point.
Architecture Générale HL Composer
Hyperledger Composer est construit autour des éléments suivants:
- Un Environnement d’exécution
- Des profils de connexion
- Un SDK JavaScript
- Une interface ligne de commande
- Un Serveur REST
- Une interface logicielle (LoopBack Connector)
- Une Interface Web (Playground)
- Un générateur de code (Yeoman)
Environnement d’exécution
Composer supporte actuellement plusieurs environnements d’exécution qui diffèrent selon l'emplacement de sauvegarde des données d'état du réseau:
- Hyperledger Fabric: l'état est sauvegardé sur les registres distribués.
- Web: l’exécution se fait dans une page web, c'est ce qui est utilisé par Playground. L'état est sauvegardé sur l'espace mémoire local du Navigateur.
- Embarqué: l’exécution se fait à l'interieur d'un processus Node.js c'est utilisé principalement pour faire des tests unitaires. L'état est sauvegardé en mémoire sous forme de paires nom:valeur.
SDK JavaScript
Cette SDK est composé d'un groupe d'API Node.js permettant de créer des applications pour intéragir avec un réseau déployé.
Ces APIs peuvent être séparés en deux catégories de modules npm:
- composer-client: API utilisé pour soumettre des transactions au réseau et effectuer les opérations d’interaction de base (CRUD) sur les ressources (Assets, Participants...) échangés ou traquées par le réseau.
- composer-admin: API utilisé pour faire de la gestion administrative des réseaux déployés autorisant des opérations comme install, start et upgrade.
Interface en ligne de commande
Permet aux développeurs et aux administrateurs de déployer et de gérer les réseaux.
Serveur REST
Cette outils permet de générer automatiquement un API Rest suivant la spécification "API (Swagger)" à partir d'une conception modélisée du réseau. En cours d’exécution, il implémente la logique derrière les opérations (CRUD) sur les ressources.
LoopBack Connector
Par défaut cette interface logicielle est utilisé par le serveur REST mais peut être utilisée directement pour créer des API REST très avancés qui ne sont pas nécessaires dans le projet traité.
Yeoman Code Generators
Cet outil est utilisé pour créer des squelettes de projets:
- Angular
- Node.js
- Squelettes des réseaux de nœuds (business networks)
HyperLedger Fabric: Aspect Réseau (infrastructure)
Fabric est l’aspect infra-structurel sous Hyperledger qui permet de mettre en place techniquement la notion de registre distribué pour les applications. Il permet aussi de définir les membres du réseau à un niveau plus général en termes de consortiums, d'organisations et de nœuds tout en définissants les règles de fonctionnement et de transaction.
Les différentes composantes du réseau
Un réseau se compose d'une combinaison de ces éléments de base.
- Les registres (Ledgers): On en retrouve un par canal.Le canal est une façon d'isoler les transaction de ses membres de celle des autres. c'est à dire que les nœuds appartenant à un même canal peuvent avoir un registre qui leur est dédié pour enregistrer leurs transactions sans que les non-membres ne puissent les voir.
- Le chaincode: le programme (smart contract) qui permet de lire et d'écrire sur les registres.
- Les nœuds (Peer): Une entité du réseau qui se charge d’exécuter le chaincode et de maintenir des registres.
- Ordonnanceurs: permettent de vérifier les transactions, de les ordonner et d'appliquer les règles établies pour le réseau.
- Autorités de certification: Permettent la création dynamique de certificats électroniques aux différentes entités du réseau et leurs utilisateurs.
Prise en main
Installation
Installation des prérequis:
- Git
- Node.js
- Docker
- Python
- Npm
- Docker-composer
L'installation peut se faire automatiquement (Ubuntu) en utilisant:
curl -O https://hyperledger.github.io/composer/latest/prereqs-ubuntu.sh
Installation de HL: La ligne de commande Hyperledger
npm i -g composer-cli
Composer-rest-server
npm i -g composer-rest-server
Yeoman generator
npm i -g generator-hyperledger-composer
Yeoman
npm i -g yo
Playground
npm i -g composer-playground
Installation de Fabric:
mkdir fabric-dev-servers cd fabric-dev-servers curl -O https://raw.githubusercontent.com/hyperledger/composer-tools/master/packages/fabric-dev-servers/fabric-dev-servers.tar.gz tar -xvf fabric-dev-servers.tar.gz ./downloadFabric.sh
Lancez Fabric en utilisant le script fourni:
./startFabric.sh
ou manuellement:
#utilisé à l’intérieur de docker-compose.yml export HOST=localhost export DIR=$(pwd)/fabric-scripts/hlfv<version_de_fabric> export DOCKER_FILE="${DIR}"/composer/docker-compose.yml #Arrêt des containnaires s'ils existent docker-compose -f "${DOCKER_FILE}" down docker-compose -f "${DOCKER_FILE}" up -d
Vérification:
#afficher les conteneurs docker ps #visualiser les logs des conteneurs pour vérifier qu'ils ont démarré sans erreurs docker logs <conteneur>
Dans un répertoire fabric-tools nous allons mettre des programmes utilitaires que nous allons réutiliser plus tard:
- configtxgen,
- configtxlator,
- cryptogen,
- discover,
- idemixgen
- orderer,
- peer,
- fabric-ca-client
pour ce faire, faut récupérer le script à cette adresse et l’exécuter comme suit (-s -d pour ne pas télécharger du contenu superflu pour le moment):
curl https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap.sh > bootstrap.sh ./bootstrap.sh -s -d
Réalisation - Prototype 0
Configuration Du Réseau
Le test ayant été fait sur mon PC certains chemins son propre à cette implémentation.
export PROJECT_PATH=/media/arezki/STORE/Blockchain export DIR=$PROJECT_PATH/fabric-dev-servers/fabric-scripts/hlfv12 export DOCKER_FILE=$DIR/composer/docker-compose.yml export FABRIC_START_TIMEOUT=10 export OUTPUT_CONFIG=arezki@p22-config.yaml export CFG_PATH=$DIR/composer GENESIS_BLK=newGenesis.block CHANNEL=newChannel.tx
cd $DIR ./startFabric.sh
#Vider le cache des network cards rm -rf ~/.composer #Generer les certificats cryptographiques pour la configuration par default cd $CFG_PATH cryptogen generate --config=crypto-config.yaml --output OUTPUT_CONFIG
#Initialisation Blockchain cd $CFG_PATH FABRIC_CFG_PATH=. configtxgen -profile ComposerOrdererGenesis -outputBlock $GENESIS_BLK
#Creation du tunnel par défaut FABRIC_CFG_PATH=. configtxgen -profile ComposerChannel -channelID composerchannel -outputCreateChannelTx $CHANNEL
#Creating PeerAdmin card cd $DIR ./createPeerAdminCard.sh
Modélisation
Modélisation Prototype0 CODE SOURCE
L'objectif de cette première approche est de réaliser un système de Broadcast simple et fonctionnel regroupant des entités de type User qui sont les acteurs du réseau qui peuvent via une transaction Broadcast créer une instance de type Message qui sera signée par l'identité de son émetteur. Le prototype implémente aussi:
- Une vérification d'identité : à travers un concept de signature (mot de passe) un utilisateur ne peut signer un message que de son nom et seulement si il est existant dans le système.
- Seul un Admin peut créer des User.
- Aucune entité ne peut créer de message à travers autre chose que la transaction de broadcast.
- Un User peut mettre à jour ces informations.
- Un utilisateur ne peut pas accéder au informations complètes d'un autre User ni d'un Admin.
- Toutes les entités peuvent lire les messages diffusés.
- On ne peut pas éditer un message diffusé.
- Des requêtes simples pour lister les messages (les plus récents en premier, pour un utilisateur spécifique ...).
Test sur Playground
Playground offre un moyen de déployer une modèle de réseau très rapidement sur un Navigateur et nous permet de ce fait de tester le bon fonctionnement des fonctionnalités de façon générale. Ici, un modèle équivalent du réseau p22_network est repris sur Playground. Pour ne pas prolonger la taille de l'enregistrement, seul la fonction principale de broadcast est démontrée. Les autres, ont été faites devant les tuteurs.
Déploiement
LES SOURCES
Pour déployer un modèle il est nécessaire de générer une archive (.bna) à partir du répertoire de développement.
cd <repertoire> composer archive create --sourceType dir --sourceName .
Pour automatiser la manœuvre de déploiement et de test, j'ai préparé quelques scripts shell qui reprennent les étapes importantes du processus:
- Le script bash mylauncher.sh permet de:
- préparer et initialiser notre réseau.
- deployer notre modèle.
- créer un utilisateur admin par défaut et se connecter avec ses identifiants.
- pinger le réseau
- générer un API-REST
- Lancement des conteneurs du réseau P22 IMA4 Prototype0...
./startFabric.sh
- Suppression des anciennes "networkCards"
rm -rf ~/.composer cd $CFG_PATH cryptogen generate --config=crypto-config.yaml --output OUTPUT_CONFIG
- Création du block d'initialisation
cd $CFG_PATH FABRIC_CFG_PATH=. configtxgen -profile ComposerOrdererGenesis -outputBlock $GENESIS_BLK
- Création du canal
FABRIC_CFG_PATH=. configtxgen -profile ComposerChannel -channelID composerchannel -outputCreateChannelTx $CHANNEL
- Création d'une carte d’accès Administrateur
cd $DIR ./createPeerAdminCard.sh
- Déploiement de l'archive contenant la logique applicative
composer network install --card PeerAdmin@hlfv1 --archiveFile $PROJECT_PATH/p22_network/p22_network@0.0.1.bna
- Lancement du réseau en utilisant la carte d'accès Administrateur
composer network start --card PeerAdmin@hlfv1 --networkName p22_network --networkVersion 0.0.1 --networkAdmin admin --networkAdminEnrollSecret adminpw
- Importation de la carte
composer card import --file ./admin@p22_network.card
- Tester si le réseau est bien lancé
composer network ping --card admin@p22_network
- Générer l'API REST
composer-rest-server -c admin@p22_network -n never -u true -d n -w true
Résultat Prototype 0
>>>Sur une machine virtuelle nous faisons le déploiement de notre réseau avec nos scripts. Nous créons donc un réseau avec:
- Un Validateur (Orderer)
- Une Autorité de certification (CA)
- Un Nœud (peer0)
pour ce faire nous lançon leurs centenaires respectifs avec cette configuration reprise dans le docker-compose.yml. Comme chaque entité du réseau doit avoir un certificat et une clé privée, nous utilisons les outils fournis pour les générer automatiquement (fabric-tools/bin/cryptogen...). La génération est automatisée grâce au modèle définit par crypto-config.yml. Suite à cela, il faut initialiser notre blockchain en créant manuellement le premier block GenesisBlock en utilisant configtxgen. Maintenant, il est nécessaire de créer un tunnel entre notre nœud et le validateur leur permettant de communiquer. Comme nous l'avons expliqué plus haut, pour interagir avec le réseau, il faut impérativement disposer d'une Business Network Card que nous créons moyennant les scripts fournis. Le script crée un utilisateur Admin par défaut qui a les privilèges Administrateurs. Nous nous connectons avec cette identité pour pouvoir installer notre modèle de réseau .bna puis nous le démarrons. Nous testons si le réseau a bien démarré et nous lançons la génération de l'API-REST sans les mesures de sécurité (sans login et en http clair pour le moment) sur le port 3000 de la VM. La seconde partie nous ne faisons qu’interagir avec le réseau en créant des utilisateurs (notez qu'ici nous utilisons l'API-REST en étant admin à défaut de login. De ce fait nous pouvons créer des USERs). Des requêtes HTTP sont envoyées avec curl sur le l'API pour aussi réaliser des "broadcasts" de messages. Le système implémente vraisemblablement toutes les fonctionnalités attendues.
Réalisation - Prototype 1
Choix de la topologie du réseau
Lors de la réalisation du prototype 0, une phase importante n'a pas été explicité relevant de la spécification du réseau lui-même car un modèle par défaut a été utilisé. Le but ayant été d'aboutir à un prototype qui permet d'appréhender les différentes étapes sans se perdre au premier passage dans les détails qui risqueraient d’obscurcir la vue d'ensemble. En revanche cette étape est expliquée ici en détails.
Après entretien avec mes tuteurs il m'a été conseillé de réaliser un réseau pour un cas de figure particulier avec un scénario d'usage orienté "métiers". Le scénario est le suivant: Imaginons que les différents ministères d'un état souhaitent mettre en place un réseau en utilisant la technologie dont il est question ici. Ces ministères coopèrent ensemble et s'échangent des messages en obéissant à des protocoles donnés pour informer mutuellement ou enclencher des procédures.
Pour faire court, réaliser une topologie semblable au prototype 0 ( UN ordonnanceur + Un noeud ) est insensée car on perdrait l'avantage d'un système distribué en centralisant mais aussi les performances seront catastrophiques sans parler de l’aspect sécurité qui n'est géré par nous qu'au niveau applicatif.
Ceci dit, il est maintenant nécessaire d'expliciter comment une transaction se déroule sur un réseau Hyperledger-Fabric pour comprendre comment dimensionner le notre.
A. Flux de transaction
Assumons qu'un réseau est en place. Un client va initier une transaction (création, modification, suppression ... d'une entrée dans le registre distribué). Il fait donc appel à l'SDK qui lance une proposition de transaction. Cette requête est simulée (calculée par l’exécution du chaincode avec les arguments soumis) par tous les nœuds qui renvoient la requête, les arguments, les résultats et les signatures des nœuds avec la version de l'entrée. Ce numéro de version permet de garantir l’intégrité des données (nous le verrons plus bas). Donc, les nœuds renvoient leurs approbations au client. Après avoir vérifié les réponses et les signatures, le client renvoie une requête d'invocation à l’ordonnanceur du réseau celui-ci vérifie encore une fois les signatures cryptographiques, les réponses des nœuds et le respect des règles établie et ajoute la transaction à sa file. Cette file est paramétrable en temps et en nombre de transactions. Une fois une des conditions validée, un ordre d'invocation est émis vers les nœuds pour mettre à jour l'entrée. C'est à ce niveau que la version de l'entrée est utile car elle permet de vérifier si le calcule a été fait avec la version la plus récente de la donnée autrement la transaction est enregistrée mais la mise à jour n'est pas faite (le calcul doit être refait).
B. Topologie
Nous avons mentionné plus haut l’existence de certaines entités pour lesquelles il est maintenant temps pour plus d'explications.
- Une Organisation: C'est le plus petit réseau possible on peut faire une analogie avec un réseau LAN (seulement une analogie). C'est à dire il permet l'interconnexion de nœuds avec leurs différents services. Dans le paradigme Hyperledger elle peut être assimilée à une organisation physique ou une entreprise avec cette notion de réseau local.
- Un consortium: C'est la résultant de l'interconnexion de plusieurs organisations.
Il est aussi utile de mentionner que l'on peut avoir plusieurs Ordonnanceurs pour une seule Organisation et même un ordonnanceur partagé par plusieurs. Par défaut il est nécessaire de créer au moins un canal au niveau de l'organisation et d'y inscrire tous les nœuds pour qu'ils puissent se parler.
Maintenant que nous savons cela nous pouvons dire que pour simuler notre réseaux de ministères il est approprié que chaque ministère soit représenté par une organisation qui, à sont tour, sera composée de plusieurs nœuds. En raison de la puissance de calcul à disposition nous nous contenterons de simuler un réseau de 2 ministères avec 2 nœuds dans chacun. Pour avoir un réseau décentralisé, il faudrait mettre en place plusieurs ordonnanceurs aussi. Mais en première approche nous nous contenterons d'un seul. Aussi nous créerons d'emblée les certificats et les clés privées de quelques utilisateurs. L'interconnexion des deux organisations constituera donc un Consortium.
C. Génération des certificats cryptographiques et des clés privées
Vidéo>> Média:P22certificates.mp4 Comme précisé plus haut toute entité du réseau doit avoir son propre contenu cryptographique (Clé privée et certificat électronique) afin de pouvoir s'identifier auprès des autres. Le standard utilisé ici est le X.509 qui est largement utilisé dans beaucoup de protocoles internet (ex:HTTPS). Grace au programme cryptogen dans la suite d'outils téléchargés il est possible de générer les artefacts cryptographiques en fournissant la topologie du réseau que l'on souhaite créer sous un format (.yaml). Il faut veiller à ce que EnableNodeOUs:true pour des raisons de classification des identités
- Pour générer la template (.yaml)
./cryptogen showtemplate > p22CryptoConfig.yaml
Dans le fichier p22CryptoConfig.yaml, nous définissons en premier l'ordonnanceur en définissant le nom de notre domaine
OrdererOrgs: - Name: Orderer Domain: p22network.com Specs: - Hostname: orderer
puis les Organisations (ministères)
PeerOrgs: - Name: Min1 Domain: min1.p22network.com EnableNodeOUs: true
Le nombre de nœuds sur Min1
Template: Count: 2
Le nombre d'utilisateurs en plus de l'administrateur sur Min1
Users: Count: 3
La même procédure pour Min2
- Name: Min2 Domain: min2.p22network.com EnableNodeOUs: true Template: Count: 2 Users: Count: 2
Sur le terminal, nous générons les artefacts cryptographiques qui seront enregistrés dans un dossier crypto-config:
cryptogen generate --config=./p22CryptoProfile.yaml
D. Création du bloc de genèse, configuration des canaux et des nœuds d'encrage
Il est possible d'accomplir les phases de configuration citées dans le titre de la section en utilisant un fichier de configuration (.yaml) et le programme configtxgen.
Configuration
Nous créons le fichier configtx.yml et nous y inscrivons les configurations suivantes:
- Declaration des différentes entités:
Organizations: - &OrdererOrg Name: OrdererOrg ID: OrdererMSP #le chemin vers les artefacts cryptographiques de l'ordonnanceur MSPDir: crypto-config/ordererOrganizations/p22network.com/msp # Les règles d'usage: ici que les vérifications de signatures soient obligatoires pour toute entité appartenant à cette ordonnanceur Policies: Readers: Type: Signature Rule: "OR('OrdererMSP.member')" Writers: Type: Signature Rule: "OR('OrdererMSP.member')" Admins: Type: Signature Rule: "OR('OrdererMSP.admin')" - &Min1 Name: Ministry1MSP ID: Ministry1MSP MSPDir: crypto-config/peerOrganizations/min1.p22network.com/msp Policies: Readers: Type: Signature Rule: "OR('Ministry1MSP.admin', 'Ministry1MSP.peer', 'Ministry1MSP.client')" Writers: Type: Signature Rule: "OR('Ministry1MSP.admin', 'Ministry1MSP.client')" Admins: Type: Signature Rule: "OR('Ministry1MSP.admin')" AnchorPeers: # Les nœuds d'encrage sont ceux utilisé pour l'écoute et la communication inter-organisation - Host: peer0.min1.p22network.com Port: 7051 - &Min2 Name: Ministry2MSP ID: Ministry2MSP MSPDir: crypto-config/peerOrganizations/min2.p22network.com/msp Policies: Readers: Type: Signature Rule: "OR('Ministry2MSP.admin', 'Ministry2MSP.peer', 'Ministry2MSP.client')" Writers: Type: Signature Rule: "OR('Ministry2MSP.admin', 'Ministry2MSP.client')" Admins: Type: Signature Rule: "OR('Ministry2MSP.admin')" AnchorPeers: # AnchorPeers defines the location of peers which can be used # for cross org gossip communication. Note, this value is only # encoded in the genesis block in the Application section context - Host: peer0.min2.p22network.com Port: 7051
- Compatibilité (facultatif):
Capabilities: Channel: &ChannelCapabilities V1_3: true Orderer: &OrdererCapabilities V1_1: true Application: &ApplicationCapabilities V1_3: true V1_2: false V1_1: false
- Configuration des règles pour les applications
Application: &ApplicationDefaults Organizations: Policies: Readers: Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" Capabilities: <<: *ApplicationCapabilities
- L'ordonnanceur:
Orderer: &OrdererDefaults # Pour le moment un seul ordonnanceur OrdererType: solo Addresses: - orderer.p22network.com:7050 BatchTimeout: 2s BatchSize: # Max Message Count: Taille Max de la file en requêtes MaxMessageCount: 10 # Taille max absolue de la mémoire alloué à la file AbsoluteMaxBytes: 99 MB # Taille max par defaut de la file PreferredMaxBytes: 512 KB #Cette partie sera configuré plutard dans le cas où nous auront plusieurs ordonnaceurs Kafka: # Brokers: A list of Kafka brokers to which the orderer connects # NOTE: Use IP:port notation Brokers: - 127.0.0.1:9092 Organizations: Policies: Readers: Type: ImplicitMeta Rule: "ANY Readers" Writers: Type: ImplicitMeta Rule: "ANY Writers" Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" # BlockValidation specifies what signatures must be included in the block # from the orderer for the peer to validate it. BlockValidation: Type: ImplicitMeta Rule: "ANY Writers"
- Le tunnel d'échange:
Channel: &ChannelDefaults Policies: # Who may invoke the 'Deliver' API Readers: Type: ImplicitMeta Rule: "ANY Readers" # Who may invoke the 'Broadcast' API Writers: Type: ImplicitMeta Rule: "ANY Writers" # By default, who may modify elements at this config level Admins: Type: ImplicitMeta Rule: "MAJORITY Admins" Capabilities: <<: *ChannelCapabilities
- Les profiles: équivalents des cibles si l'on fait une analogie avec un Makefile
Profiles: MultiMinistryOrdererGenesis: <<: *ChannelDefaults Orderer: <<: *OrdererDefaults Organizations: - *OrdererOrg Capabilities: <<: *OrdererCapabilities Consortiums: MinistryConsortium: Organizations: - *Min1 - *Min2 InterMinistryChannel: Consortium: MinistryConsortium Application: <<: *ApplicationDefaults Organizations: - *Min1 - *Min2 Capabilities: <<: *ApplicationCapabilities P22DevModeKafka: <<: *ChannelDefaults Capabilities: <<: *ChannelCapabilities Orderer: <<: *OrdererDefaults OrdererType: kafka Kafka: Brokers: - kafka.p22network.com:9092 Organizations: - *OrdererOrg Capabilities: <<: *OrdererCapabilities Application: <<: *ApplicationDefaults Organizations: - <<: *OrdererOrg Consortiums: MinistryConsortium: Organizations: - *Min1 - *Min2
Génération
Maintenant que notre fichier de configuration est prêt nous procédons à la génération:
- Le Bloc de genèse:
mkdir p22ChannelArtefacts configtxgen -profile MultiMinistryOrdererGenesis -channelID sys-channel -outputBlock ./p22ChannelArtefacts/genesis.block
Le bloc de genèse (Genesis Block) permet l'initialisation de la blockchain mais aussi la sauvegarde de toute la configuration du réseau de façon immuable dans le registre distribué lui-même. De cette manière celle-ci n'est modifiable qu'en passant par une procédure spéciale nécessitant une authentification Administrateur ou l'arrêt total. En parallèle, la création du tunnel par défaut a été faite.
- Le canal inter-organisation:
configtxgen -profile InterMinistryChannel -outputCreateChannelTx ./p22ChannelArtefacts/channel.tx -channelID mychannel
- Le nœud d'encrage sur le ministère 1:
configtxgen -profile InterMinistryChannel -outputAnchorPeersUpdate ./p22ChannelArtefacts/Ministry1MSPanchors.tx -channelID mychannel -asOrg Ministry1MSP
- Le nœud d'encrage sur le ministère 2:
configtxgen -profile InterMinistryChannel -outputAnchorPeersUpdate ./p22ChannelArtefacts/Ministry2MSPanchors.tx -channelID mychannel -asOrg Ministry2MSP
A la fin de cette étape le répertoire "p22ChannelArtefacts" doit contenir les fichiers suivants:
├── Ministry1MSPanchors.tx ├── Ministry2MSPanchors.tx ├── channel.tx └── genesis.block
E. Configuration des conteneurs
Vu que nous travaillons avec docker et en vue du nombre de conteneurs que nous devons lancer et configurer il est nécessaire d'automatiser cette tâche. Plusieurs systèmes de gestion de conteneurs peuvent faire le travail.De ce fait l'usage de docker n'est pas indispensable mais en vue de la présence d'une meilleure documentation pour celui-ci, il est préférable de l'utiliser. Nous utiliseront docker-compose pour créer les scripts de déploiement. Vue que nous voulons implémenter un réseau avec un ordonnanceur et 4 nœuds il est donc intuitif de préparer un conteneur pour chacun d'eux. Pour mieux gérer ce réseau on va aussi ajouter un conteneur qui va nous servir de ligne de commande pour effectuer les interactions avec le réseau en le configurant avec les variables d'environnement et le contenu nécessaire. De ce fait nous gardons un environnement propre. Vu que tous les nœuds auront plus ou moins la même configuration à quelques détails près il sera donc judicieux de faire une configuration de base (peer-base.yaml) et la faire hériter par les différents nœuds.
- peer-base.yaml
services: peer-base: image: hyperledger/fabric-peer:$IMAGE_TAG environment: - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=${COMPOSE_PROJECT_NAME}_p22network - FABRIC_LOGGING_SPEC=INFO - CORE_PEER_TLS_ENABLED=true - CORE_PEER_GOSSIP_USELEADERELECTION=true - CORE_PEER_GOSSIP_ORGLEADER=false - CORE_PEER_PROFILE_ENABLED=true - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: peer node start
- docker-compose-base.yaml
Ce fichier abordera les variables d'environnement les volumes et les ports TCP plus spécifiques à chaque entité. Il s'agit aussi de monter les artefacts cryptographiques générés précédemment. Ici seule la configuration de l'ordonnanceur et celle de peer0 de Min1 sont explicitées mais celles des autres nœuds peuvent être facilement retrouvées ici.
peer0.min1.p22network.com: container_name: peer0.min1.p22network.com extends: file: peer-base.yaml service: peer-base environment: - CORE_PEER_ID=peer0.min1.p22network.com - CORE_PEER_ADDRESS=peer0.min1.p22network.com:7051 - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.min1.p22network.com:7051 - CORE_PEER_GOSSIP_BOOTSTRAP=peer0.min1.p22network.com:7051 - CORE_PEER_LOCALMSPID=Ministry1MSP volumes: - /var/run/:/host/var/run/ - ../crypto-config/peerOrganizations/min1.p22network.com/peers/peer0.min1.p22network.com/msp:/etc/hyperledger/fabric/msp - ../crypto-config/peerOrganizations/min1.p22network.com/peers/peer0.min1.p22network.com/tls:/etc/hyperledger/fabric/tls - peer0.min1.p22network.com:/var/hyperledger/production ports: - 7051:7051 - 7053:7053
orderer.p22network.com: container_name: orderer.p22network.com image: hyperledger/fabric-orderer:$IMAGE_TAG environment: - FABRIC_LOGGING_SPEC=INFO - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0 - ORDERER_GENERAL_GENESISMETHOD=file - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block - ORDERER_GENERAL_LOCALMSPID=OrdererMSP - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp # enabled TLS - ORDERER_GENERAL_TLS_ENABLED=true - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt] - ORDERER_KAFKA_TOPIC_REPLICATIONFACTOR=1 - ORDERER_KAFKA_VERBOSE=true working_dir: /opt/gopath/src/github.com/hyperledger/fabric command: orderer volumes: - ../p22ChannelArtefacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block - ../crypto-config/ordererOrganizations/p22network.com/orderers/orderer.p22network.com/msp:/var/hyperledger/orderer/msp - ../crypto-config/ordererOrganizations/p22network.com/orderers/orderer.p22network.com/tls/:/var/hyperledger/orderer/tls - orderer.p22network.com:/var/hyperledger/production/orderer ports: - 7050:7050
Maintenant que ces configurations de base sont faites:
mkdir base mv docker-compose-base.yaml ./base mv peer-base.yaml ./base
- docker-compose.yaml: Le fichier principal
volumes: orderer.p22network.com: peer0.min1.p22network.com: peer1.min1.p22network.com: peer0.min2.p22network.com: peer1.min2.p22network.com: networks: p22network: services: ########################################################## orderer.p22network.com: extends: file: base/docker-compose-base.yaml service: orderer.p22network.com container_name: orderer.p22network.com networks: - p22network ########################################################## peer0.min1.p22network.com: container_name: peer0.min1.p22network.com extends: file: base/docker-compose-base.yaml service: peer0.min1.p22network.com networks: - p22network ########################################################## peer1.min1.p22network.com: container_name: peer1.min1.p22network.com extends: file: base/docker-compose-base.yaml service: peer1.min1.p22network.com networks: - p22network ... ... ...
Aussi la configuration du conteneur qui va nous servir de ligne de commande:
cli: container_name: cli image: hyperledger/fabric-tools:$IMAGE_TAG tty: true stdin_open: true environment: - GOPATH=/opt/gopath - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock - FABRIC_LOGGING_SPEC=DEBUG - CORE_PEER_ID=cli - CORE_PEER_ADDRESS=peer0.min1.p22network.com:7051 - CORE_PEER_LOCALMSPID=Ministry1MSP - CORE_PEER_TLS_ENABLED=true - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/min1.p22network.com/peers/peer0.min1.p22network.com/tls/server.crt - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/min1.p22network.com/peers/peer0.min1.p22network.com/tls/server.key - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/min1.p22network.com/peers/peer0.min1.p22network.com/tls/ca.crt - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/min1.p22network.com/users/Admin@min1.p22network.com/msp working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer command: /bin/bash volumes: - /var/run/:/host/var/run/ - ./chaincode:/opt/gopath/src/github.com/chaincode - ./crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/ - ./p22ChannelArtefacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts depends_on: - orderer.p22network.com - peer0.min1.p22network.com - peer1.min1.p22network.com - peer0.min2.p22network.com - peer1.min2.p22network.com networks: - p22network
Vous remarquerez que nous y avons monté les volumes:
- chaincode: qui va contenir les sources de l'application.
- crypto-config: les certificats et les clés générés précédemment.
- scripts: les scripts qui vont nous permettre d'automatiser quelques tâches et qui seront présentés plus bas.
- p22ChannelArtefacts: contient les artefacts pour le canal et les nœuds d'encrage générés précédemment.
- Lancement:
IMAGE_TAG=latest docker-compose -f docker-compose.yaml up -d
- Arrêt:
IMAGE_TAG=latest docker-compose -f docker-compose.yaml down -d
Nota Bene: parfois il est nécessaire d'effectuer le nettoyage des résidus des lancements précédents n'ayant pas été arrêtés correctement.
docker stop $(docker ps -a -q) docker rm $(docker ps -a -q)
mais il faut savoir que ceci arrête tous les conteneurs en cours d’exécution sur docker.
Automatisation du déploiement du réseau
Maintenant que nous avons en main les différentes manœuvres pour lancer notre système, il est nécessaire d'automatiser ces étapes et d'ajouter des options utiles au processus pour de futures développements ou modifications. Comme annoncé précédemment nous n'utilisons qu'un seul ordonnanceur pour le moment et de ce fait dans notre fichier de configuration nous avons choisis ordererType:solo mais si nous avons le temps plus tard nous en configurerons plusieurs en utilisant le mode "Kafka". Il serait judicieux de prévoir ainsi un moyen de passer rapidement vers ce mode. Aussi pour sauvegarder l'état du réseau pour le moment et par défaut celui-ci est enregistré directement sur la mémoire des nœuds en entraînant de possible pertes (coupure électrique). Il sera par la suite utile de sauvegarder dans une base de donnée (couchedb). Le développement du chaincode est supporté au moment de l'écriture avec 3 langages "go", "nodeJs" et "Java" à condition de paramétrer environnement selon le choix. Ces options restent donc à étudier en plus de détails plus tard mais tout de même à prévoir.
Les grandes lignes du travail accompli est donc de:
- Permettre de regénérer si besoin les artefacts cryptographiques.
- Permettre de régénérer aussi le bloc de genèse, les configs de nœuds d'encrage ...etc
- Permettre de démarrer le réseau à partir de la configuration.
- Permettre d'ajouter les options.
- Se déplacer vers le conteneurs "cli" avec un "docker exec" afin d'exécuter les scripts de déploiement et d'installation de chaincode.
- Arrêter proprement le réseau.
- Nettoyer l'environnement.
Le script en question est le suivant >>> MinistriesNet
Automatisation de l'installation et de l’instanciation du chaincode
Souvenez-vous qu'en configurant les conteneurs nous avons monté un dossier "scripts" qui doit contenir les scripts dont il est question ici. En se basant sur les fonctions contenu dans cet exemple nous mettons en place un script permettant d’utiliser ces fonctions afin d’exécuter certaines taches pour finaliser le lancement du réseau et l'installation automatique du chaincode sur les nœuds. Ce fichier utils.sh contient les fonctions suivantes
- verifyResult()
- setOrdererGlobals()
- setGlobals()
- updateAnchorPeers()
- joinChannelWithRetry()
- installChaincode()
- upgradeChaincode()
- chaincodeQuery()
- fetchChannelConfig()
- signConfigtxAsPeerOrg()
- createConfigUpdate()
- parsePeerConnectionParameters()
- chaincodeInvoke()
Que nous avons adaptées à notre réseau en modifiant les variables d'environnement et les chemins.
On peut utiliser ces dernières dans notre script.sh que nous allons créer en ajoutant cette instruction qui a la valeur d'un import en bash
. utils.sh
Les fonctions essentielles de ce script sont:
createChannel() { #if TLS Off ... peer channel create -o orderer.p22network.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx >&log.txt ... #else ... peer channel create -o orderer.p22network.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA >&log.txt ... }
joinChannel () { for min in 1 2; do for peer in 0 1; do joinChannelWithRetry $peer $min ... done done }
... updateAnchorPeers 0 1 updateAnchorPeers 0 2 ...
Ces dernières permettent d'appliquer les configurations des artefacts générés au réseau actuel (créer le canal en vrai) puis de faire en sorte que les nœuds rejoignent ce canal. Une fois ceci fait, appliquer les configurations pour les nœuds d'encrage.
Un autre point important: on doit spécifier la variable d’environnement CC_SRC_PATH indiquant le chemin vers les sources du chaincode et LANGUAGE le langage de développement utilisé.
Pour installer le chaincode sur un nœud donné:
installChaincode <peer_num> <Min_num>
Pour instancier le chaincode sur un nœud donné:
instantiateChaincode <peer_num> <Min_num>
Grâce aux paramètres <peer_num> <Min_num>, dans les fonctions adaptées plus haut, les bonnes variables d'environnement sont initialisées. Je vous invite à consulter le fichier utils.sh pour plus de détails. Mais sachez que nous reviendrons sur ce point de façon plus détaillée et explicite plus bas.
Test bout à bout du réseau
>>>
En utilisant un exemple de chaincode et en lançant le script de déploiement avec les scripts discuté précédemment, nous retraçons toutes les phases décrites jusqu'ici. En suite, arrive la phase d' invocation du chaincode de test auquel nous soumettons des requêtes de calcul avec des arguments puis nous comparons les réponses avec les résultats attendus. Ceci est donc une confirmation que le réseau est bien fonctionnel.
Développement de la logique applicative
Nous parlerons ici des fonctionnalités qu'implémentera le chaincode que nous allons développer pour les noeuds. Dans le contexte de notre application de broadcast de messages. Pour installation du chaincode nous avons mis en place un script spécifique dans le dossier scripts
arezki@blockchain:~/Blockchain/p22NetworkArtefacts$ tree scripts scripts ├── InstallMyCC.sh <--- Script d'installation ├── addUser.sh ├── broadcastMsg.sh ├── broadcastSpam.sh ├── broadcastUserNotExist.sh ├── broadcastWrongPass.sh ├── queryUser.sh ├── queryUserMsgs.sh ├── script.sh ├── scriptWithTest.sh └── utils.sh
ce script permet d'installer le chaincode sur tous les noeuds de notre réseau en modifiant les variables d'environnement à chaque fois. Ensuite, il l'initialise sur l'un des noeuds car il n'est necessaire d'initialiser qu'une fois sur un seul noeud. La documentation relative à l'installation se trouve ici.
A. Choix du langage
Comme annoncé précedemment le développement peut se faire avec plusieurs languages, mais nous préférerons le faire en Java pour la familiarité avec ce dernier et son rapport avec les cours vu durant cette année. Nous utiliserons pour la gestion des dépendances l'outil Gradle car il est nécessaire pour que les noeud puissent faire le build au moment de l'installation du chaincode. Notre répértoire de développement doit ressembler quelque chose de ce type là.
publicAnnouncement ├── build.gradle ├── settings.gradle └── src └── main └── java └── org └── hyperledger └── fabric └── p22network └── P22Chaincode.java
Pour la gestion des dépendences de ce projet:
- build.gradle
plugins { id 'com.github.johnrengelman.shadow' version '2.0.3' id 'java' } group 'org.hyperledger.fabric-chaincode-java' version '1.0-SNAPSHOT' sourceCompatibility = 1.8 repositories { mavenLocal() mavenCentral() } dependencies { compile group: 'org.hyperledger.fabric-chaincode-java', name: 'fabric-chaincode-shim', version: '1.+' compile group: 'org.json', name: 'json', version: '20180813' } shadowJar { baseName = 'chaincode' version = null classifier = null manifest { attributes 'Main-Class': 'org.hyperledger.fabric.p22network.P22Chaincode' } }
Pour compiler:
arezki@blockchain:~/Blockchain/p22NetworkArtefacts/chaincode/publicAnnouncement$ gradle build
B. Java Chaincode API
Fabric Propose un API Shim pour gèrer l'interraction avec le chaincode.Tout code doit impérativiment implémenter l'interface chaincode dont les méthodes sont exécutées à la reception des propositions de transaction. Ces methodes sont:
- Invoke : pour soumettre des requêtes de transaction (Lecture/écriture sur le registre distribué).
- Init : fonction d'initialisation. ne se lance qu'une fois.
C. Stockage et structure de données
Pour plus de simplicité et afin d'aboutir plus rapidement à un prototype fonctionnel nous optons pour un stockage utilisant stateDB pour le maintien du registre distribué. Cette base de données se présente sous forme de couples <clé : valeur>. Le seul compromis que nous faisons contrairement à l'usage d'un autre système de stockage plus évolué tel que coucheDB est le fait de ne pas bénéficier des fonctionnalités de requêtes riches. Ceci n'est pas vraiment un problème car nous avons une solution, qui, dans le cadre de l'application que nous souhaitons réaliser, nous permettra de nous en affranchir:
Sur stateDB les possibilités offertes par l'API sont le stockage:
<clé(String) : valeur (byte[])> : en utilisant putState().
<clé(String) : valeur (String)> : en utilisant putStringState().
La solution que nous proposons est d'utiliser la seconde combiné à la library org.json nous permettant d'utiliser des structures de données avancées (Objets JSON) et une particularité essentielle de sérialisation et de désérialisation en String pour faciliter le stockage. Vous avez sans doute remarqué qu'elle a été ajoutée à notre fichier de gestion des dépendances.
En ce qui est de la structure de données nous aurons un Id pour clé représentant l'Identifiant d'un utilisateur du système. La valeur, comme annoncé précédemment, sera un structure User représentée par ce squelette Json:
{ "Identity":{ "NAME" : ....., "ROLE" : ....., "PWD" : ....., "AFFIL": ....., "CERT" : ..... }, "Messages":[ {.......}, {.......}, ....... ] }
La clé Messages représentera un tableau qui contiendra des Objets de type Message représenté ci-dessous:
{ "ID" : ......, "TIME" : ......, "TITLE" : ......, "CONTENT" : ...... }
D. Fonctions Principales
package org.hyperledger.fabric.p22network; import ... public class P22Chaincode extends ChaincodeBase { ... @Override public Response init(ChaincodeStub stub) { ... ... } @Override public Response invoke(ChaincodeStub stub) { try { String func = stub.getFunction(); List<String> params = stub.getParameters(); if (func.equals("addUser")) { return addUser(stub, params); } if (func.equals("delUser")) { return delUser(stub, params); } if (func.equals("queryUser")) { return queryUser(stub, params); } if (func.equals("broadcastMsg")) { return broadcastMsg(stub, params); } return newErrorResponse("Invalid invoke function name. Expecting one of: [addUser, delUser, queryUser, broadcastMsg]"); } catch (Throwable e) { return newErrorResponse(e); } } // create a chaincode user private Response addUser(ChaincodeStub stub, List<String> args) { ... ... } // Deletes an entity from the world state private Response delUser(ChaincodeStub stub, List<String> args) { ... ... } // Find a user entry in the storage private Response queryUser(ChaincodeStub stub, List<String> args) { ... ... } // broadcast a Message private Response broadcastMsg(ChaincodeStub stub, List<String> args) { ... ... } // MAIN public static void main(String[] args) { new P22Chaincode().start(args); } }
Tests de fonctionnement
A partir du conteneur cli nous pouvons, grâce au CLI API de Fabric nous pouvons lancer des requêtes d'invocation depuis le terminal et ainsi tester le bon fonctionnement avec quelques scripts shell.
- addUser.sh: ajouter un utilisateur client cette requête ne marche que si l'invocateur est administrateur
#!/bin/bash # Expecting: Id, UserName, UserMinistry, UserPWD, adminID, adminPWD peer chaincode invoke -o orderer.p22network.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n p22CC -c '{"Args":["addUser","001","user1","Min1","passwdofuser1","000","passwdofarezki"]}'
resultat:
... ... 2019-05-05 21:25:37.128 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 04f Chaincode invoke successful. result: status:200 message:"User added Successfully:\n" payload:"{\"Messages\":[],\"Identity\":{\"ROLE\":\"Client\",\"AFFIL\":\"Min1\",\"CERT\":\"null\",\"PWD\":\"passwdofuser1\",\"NAME\":\"user1\"}}"
- broadcastMsg.sh: poster un message
#!/bin/bash # Expecting: UserId , userPWD, MsgTitle , MsgContent peer chaincode invoke -o orderer.p22network.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n p22CC -c '{"Args":["broadcastMsg","001","passwdofuser1","Viva la vida","Lorem epsum in dolore"]}'
resultat:
... ... 19-05-05 21:27:43.467 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 04f Chaincode invoke successful. result: status:200 message:"Message broadcasted Successfully:\n" payload:"{\"Messages\":[{\"TIME\":\"2019-05-09T21:27:43.407585253Z\",\"TITLE\":\"Viva la vida\",\"CONTENT\":\"Lorem epsum in dolore\",\"ID\":\"70b4817e6c43c8711711c89ed0981d7e35b3730e93e6c49ab4a177200eaa2c55\"}],\"Identity\":{\"ROLE\":\"Client\",\"AFFIL\":\"Min1\",\"CERT\":\"null\",\"PWD\":\"passwdofuser1\",\"NAME\":\"user1\"}}"
- broadcastMsgUserNotExist.sh: poster un message avec un utilisateur non-existant
#!/bin/bash # Expecting: UserId , userPWD, MsgTitle , MsgContent peer chaincode invoke -o orderer.p22network.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n p22CC -c '{"Args":["broadcastMsg","9999","passwdofuser999","Viva la vida","Lorem epsum in dolore"]}'
resultat:
... ... 2019-05-05 21:29:45.070 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> DEBU 04c ESCC invoke result: response:<status:500 message:"transaction returned with failure: \nError: USER WITH ID [9999] DOES NOT EXIST\n" > Error: endorsement failure during invoke. response: status:500 message:"transaction returned with failure: \nError: USER WITH ID [9999] DOES NOT EXIST\n"
- broadcastWrongPass.sh: poster un message avec un mauvais mot de passe pour l' Id utilisateur fourni
#!/bin/bash # Expecting: UserId , userPWD, MsgTitle , MsgContent peer chaincode invoke -o orderer.p22network.com:7050 --tls true --cafile $ORDERER_CA -C mychannel -n p22CC -c '{"Args":["broadcastMsg","001","wrongpasswd","Hackeur du dimanche","Spending some time making examples for demo"]}'
resultat:
... ... 2019-05-05 21:32:07.955 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> DEBU 04c ESCC invoke result: response:<status:500 message:"transaction returned with failure: \nError: WRONG PASSWORD. NO RIGHTS TO PUBLISH" > Error: endorsement failure during invoke. response: status:500 message:"transaction returned with failure: \nError: WRONG PASSWORD. NO RIGHTS TO PUBLISH"
...
Les résultats des tests semblent concluants.
Développement de l'application client
Sur Fabric, l'application client est ce qui relie notre chaincode déployé sur le réseau au monde extérieur. Cette intéraction passe à travers le SDK qui est diponibles dans plusieurs languages (Java, NodeJs). Nous utiliserons cette fois le SDK Node pour deux principales raisons:
- Documentation plus importante qu'en Java.
- Facilité de créer un API rest moyennant des packages javaScript.
Les packetages NPM du SDK sont:
- fabric-client: fonctions nécessaires à l'instantiation, la soumission des requêtes et des transactions vers le réseau.
- fabric-ca-client: pour interragir avec les authorités de certification de Hyperledger Fabric. Gestion des enregistrement des clients et des rôles.
A. Configuration de l'accès
Il question dans cette partie d'expliquer comment un client pourra accèder à notre réseau et interragir avec lui. Avant de pouvoir faire celà un client doit déjà être enregistré pour avoir ces identifiants et ces certificats. Ce processus d'enregistrement est fait par un administrateur auprès d'une authorité de certification. Mais avant de parler ça nous abordons une partie toute aussi importante. Les profils de connexion.
a. Profils de connexion
Un profil de connexion est un moyen de conserver les informations necessaires sur l'infrastructure de notre réseau pour que nos clients puissent s'y connecter. Il contient entre autres les urls vers les différentes entités ainsi que les certificats cryptographiques necessaires.
arezki@blockchain:~/Blockchain/p22NetworkArtefacts/client$ cat connexion.json { "name": "p22network", "x-commitTimeout": 300, "version": "2.0.0", "client": { "organization": "Min1", "connection": { "timeout": { "peer": { "endorser": "300", "eventHub": "300", "eventReg": "300" }, "orderer": "300" } } }, "channels": { "composerchannel": { "orderers": ["orderer.p22network.com"], "peers": { "peer0.min1.p22network.com": {} } } }, "organizations": { "Min1": { "mspid": "Ministry1MSP", "peers": ["peer0.min1.p22network.com"], "certificateAuthorities": ["ca.min1.p22network.com"] } }, "orderers": { "orderer.p22network.com": { "url": "grpc://localhost:7050", "tlsCACerts": { "pem": "-----BEGIN CERTIFICATE-----MIICTzCCAfagA... -----END CERTIFICATE-----" } } }, "peers": { "peer0.min1.p22network.com": { "url": "grpc://localhost:7051", "tlsCACerts": { "pem": "-----BEGIN CERTIFICATE-----MIICYzCCA... -----END CERTIFICATE-----" } } }, "certificateAuthorities": { "ca.min1.p22network.com": { "url": "https://localhost:7054", "caName": "ca.min1.p22network.com" }, "tlsCACerts": { "pem": "-----BEGIN CERTIFICATE-----MIICXTCCAgOgAwI.... -----END CERTIFICATE-----" } }
b. Authorités de certification
Les autorités de certification servent à fournir, révoquer ou verifier des certificats. Pour avoir accès à ce service, il existe pour Fabric un conteneur spécial remplissant cette fonction fabric-ca.Etant donné que nous avons deux organisations (Ministères) il va donc falloir en créer deux. Pour ce faire, nous apportons a notre fichier docker-compose.yaml les lignes suivantes:
services: #adding a certificate authority for Min1 ca.min1.p22network.com: image: hyperledger/fabric-ca:latest environment: - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server - FABRIC_CA_SERVER_CA_NAME=ca.min1.p22network.com - FABRIC_CA_SERVER_TLS_ENABLED=true - FABRIC_CA_SERVER_DEBUG=true - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/3ee81323a141a0cfd7e5071b75621b1abbf648eb610fe37b17caeb8a88872cd0_sk ports: - "7054:7054" command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.min1.p22network.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/3ee81323a141a0cfd7e5071b75621b1abbf648eb610fe37b17caeb8a88872cd0_sk -b arezki:pwdofarezki -d' volumes: - ./crypto-config/peerOrganizations/min1.p22network.com/ca/:/etc/hyperledger/fabric-ca-server-config container_name: ca.min1.p22network.com
#adding a certificate authority for Min2 ca.min2.p22network.com: image: hyperledger/fabric-ca:latest environment: - FABRIC_CA_HOME=/etc/hyperledger/fabric-ca-server - FABRIC_CA_SERVER_CA_NAME=ca.min2.p22network.com - FABRIC_CA_SERVER_TLS_ENABLED=true - FABRIC_CA_SERVER_DEBUG=true - FABRIC_CA_SERVER_CA_KEYFILE=/etc/hyperledger/fabric-ca-server-config/0e7aa85027f1bdb5953b69e781f98e7084ec4178575af645464344b8532683aa_sk ports: - "8054:7054" command: sh -c 'fabric-ca-server start --ca.certfile /etc/hyperledger/fabric-ca-server-config/ca.min2.p22network.com-cert.pem --ca.keyfile /etc/hyperledger/fabric-ca-server-config/0e7aa85027f1bdb5953b69e781f98e7084ec4178575af645464344b8532683aa_sk -b arezki:pwdofarezki -d' volumes: - ./crypto-config/peerOrganizations/min2.p22network.com/ca/:/etc/hyperledger/fabric-ca-server-config container_name: ca.min2.p22network.com
c. Gestion des utilisateurs
adminEnrollment.js
En utilisant le SDK sur NodeJs, nous enregistrons l'utilisateur administrateur auprès de l'autorité de certification. Une fois, fois que nous avons un administrateur nous pouvons enregistrer des clients. Le résultat de cette opération et la génération d'un couple Clé privée / clé publique et d'un certificat pour l'administrateur.
registerUser.js
Nous montrons ici comment enregister un utilisateur "user1" auprès de l'autorité de certification. Le résultat de cette opération et la génération d'un couple Clé privée / clé publique et d'un certificat pour l'utilisateur "user1".
chaincodeInvoke.js {problème}
Cette partie est supposée nous permettre d'invoquer notre chaincode et ainsi d'executer des transactions. Malheureusement, nous n'arrivons pas à determiner l'origine du problème empêchant la communication entre le script et le réseau malgré le fait qu'ils soient tous les deux en localhost.
B. API REST
En raison, du problème percistant à l'invocation du chaincode avec chaincodeInvoke.js. Nous n'avons pas pu finir cette partie. Néanmoins, en voici les grandes lignes:
- Création des chemins: en utilisant les Packetages express et body-parser nous pouvons créer un serveur web allouer routes pour executer les fonctions d'invocation comme peut l'illustrer cet exemple:
const express = require('express') const app = express() var bodyParser = require('body-parser') app.get('/api/msg', (req, res) => { // ...queryMsg }); app.post('/api/msg', (req, res) => { // ...broadcastMsg }); app.get('/api/users', (req, res) => { // ...queryUser }); app.post('/api/users', (req, res) => { // ... addUser }); app.delete('/api/users', (req, res) => { // ...delUser }); app.listen(2020, () => console.log(`Serveur en écoute sur port 2020!`), );
- Création d'une interface web simple: deux menus (Utilisateur/Admin) avec un champs de text pour remplir les arguments.
Test Finaux
//non lieu
Propositions d'amélioration
Durant cette première approche introductive, beaucoup de décisions ont été prises lors de la réalisation de façon à simplifier le travail. Ce qui offre des possibilités d'amélioration importantes:
- Déverminer les fonctionnalités non-abouties.
- Implémenter l'interface web.
- Revoir l'architecture du réseau: ajouter notemment des ordonnanceurs pour décentraliser le travail (Kafka).
- Etoffer les fonctionnalités implémentées par le chaincode par des fonctions de recherches avancées.
- Utiliser la base de données CouchDB pour avoir accès à des fonctionnalités avancées.
- Explorer plus en profondeur la gestion de l'accès.
- Implémenter sur un vrai réseau et non en localhost.
Conclusion Générale
Les champs d’exploitation de la technologie blockchain sont immenses : banques, assurance, santé et industrie pharmaceutique, supply chain de nombreux secteurs (agroalimentaire, luxe, commerce international, distribution, vins, aéronautique, automobile…), industrie musicale, énergie, immobilier, vote…
Surtout, la blockchain ouvre la voie d’un nouveau web, le web décentralisé, et d’une nouvelle économie numérique. Bien évidemment, ces promesses ne sont pas exemptes de défis, qu’ils soient économiques, juridiques, de gouvernance, ou encore écologiques.
Malgré que le projet n'a pas abouti à 100% à cause d'un soucis sur la phase finale de test. Il aura été d'un grand interêt car il a constitué une opportunité de travailler sur une technologie innovante et d'aborder beaucoup de sujets intéressants et d'actualité.
Feuille d'heures
Tâche | Prélude | Heures S1 | Heures S2 | Heures S3 | Heures S4 | Heures S5 | Heures S6 | Heures S7 | Heures S8 | Heures S9 | Heures S10 | Total |
---|---|---|---|---|---|---|---|---|---|---|---|---|
Wiki | 8 | 4 | 4 | 5 | 2 | 5 | 5 | |||||
Analyse du projet | 12 | |||||||||||
Préparation de l'environnement de développement | 3 | |||||||||||
Prise en main des outils | 4 | 8 | 2 | |||||||||
Réalisation du prototype 0 | 3 | 4 | 4 | |||||||||
Réalisation du prototype 1 | 12 | 20 | 25 | 24 |
Ne sont pas comprises les journées entières des weeks ends et vacances.
Modification de IMA4 2018_2019 P22 (section) — Wiki de Projets IMA
Prologue
Documents Rendus
Git: https://github.com/Arezki1995/Blockchain
Rapport
Références
Fonctionnement et concepts:
https://media.readthedocs.org/pdf/hyperledger-fabric/release-1.4/hyperledger-fabric.pdf
https://hyperledger-fabric.readthedocs.io/en/release-1.4/txflow.html
https://hyperledger-fabric.readthedocs.io/en/release-1.4/arch-deep-dive.html
https://hyperledger-fabric.readthedocs.io/en/release-1.4/functionalities.html
https://hyperledger-fabric.readthedocs.io/en/release-1.4/smartcontract/smartcontract.html
Les commandes:
https://hyperledger-fabric.readthedocs.io/en/release-1.4/command_ref.html
Exemples:
https://github.com/hyperledger/fabric-samples/tree/release-1.4/basic-network
https://github.com/hyperledger/fabric-samples/blob/release-1.4/first-network/byfn.sh
https://fabric-ca.readthedocs.io/en/latest/users-guide.html
Divers:
https://hyperledger-fabric.readthedocs.io/en/release-1.4/couchdb_as_state_database.html
https://docs.oracle.com/javase/7/docs/api/java/security/cert/X509Certificate.html
https://docs.oracle.com/javase/7/docs/api/java/security/cert/CertificateFactory.html
https://stleary.github.io/JSON-java
Application Client
https://fabric-sdk-node.github.io/release-1.4/index.html
Glossaire
https://hyperledger-fabric.readthedocs.io/en/release-1.2/glossary.html