美文网首页
使用fabric-sdk-node的示例2

使用fabric-sdk-node的示例2

作者: 链播学院 | 来源:发表于2019-03-22 17:01 被阅读0次

    0 导言

    fabric-sdk-node也是分两种写法,一种是底层写法,一种是比较高层的写法。下面先演示比较高层的写法。借助于fabric-network这个模块可以写更加简捷的代码。

    本文档演示了一个汽车资产管理的例子,官方提供相应的链码和客户端示例代码。

    1 创建项目目录

    注:如果已经有该目录则不需 创建了

    $ cd $GOPATH/src/github.com
    $ mkdir -p fabric-study/sdk-node-study1
    

    注:如果上述mkdir 不能执行,可能是没有权限,加上sudo就可以了

    $ sudo mkdir -p fabric-study/sdk-node-study1
    

    2 搭建运行网络

    我们不另行去搭建节点网络了,直接拷贝官网提供的basic-network过来用,执行cp命令进行拷贝.

    $ cd fabric-study/sdk-node-study1/
    $ cp -r ../../hyperledger/fabric-samples/basic-network ./
    

    basic-network会创建如下节点

    序号 组织 IP 域名 端口映射 节点
    docker 容器1 172.18.0.6 orderer.example.com 0.0.0.0:9051->7051/tcp, 0.0.0.0:9053->7053/tcp orderer节点
    docker 容器2 组织1 - org1 172.18.0.7 peer0.org1.example.com 0.0.0.0:10051->7051/tcp, 0.0.0.0:10053->7053/tcp peer1节点
    docker 容器3 172.18.0.6 cli客户端
    docker 容器4 172.18.0.6 couchDB服务器
    docker 容器5 172.18.0.6 ca服务器

    3 创建链码放置目录

    在这里我们不打算自己编写链码了,直接使用官方提供的fabcar示例的链码,如若对该链码不了解,可通过阅读该链码的源码来熟悉它

    $ mkdir chaincode
    $ cp -r ../../hyperledger/fabric-samples/chaincode/fabcar ./chaincode
    

    4 创建app1目录

    $ mkdir app2
    

    5 用vscode打开sdk-node-study2

    Snipaste_2019-03-22_16-58-32.png

    6 在app1下创建package.json

    内容如下

    {
        "name": "fabcar",
        "version": "1.0.0",
        "description": "FabCar application implemented in JavaScript",
        "engines": {
            "node": ">=8",
            "npm": ">=5"
        },
        "scripts": {
            "lint": "eslint .",
            "pretest": "npm run lint",
            "test": "nyc mocha --recursive"
        },
        "engineStrict": true,
        "author": "Hyperledger",
        "license": "Apache-2.0",
        "dependencies": {
            "fabric-ca-client": "~1.4.0",
            "fabric-network": "~1.4.0"
        },
        "devDependencies": {
            "chai": "^4.2.0",
            "eslint": "^5.9.0",
            "mocha": "^5.2.0",
            "nyc": "^13.1.0",
            "sinon": "^7.1.1",
            "sinon-chai": "^3.3.0"
        },
        "nyc": {
            "exclude": [
                "coverage/**",
                "test/**"
            ],
            "reporter": [
                "text-summary",
                "html"
            ],
            "all": true,
            "check-coverage": true,
            "statements": 100,
            "branches": 100,
            "functions": 100,
            "lines": 100
        }
    }
    

    7 创建enrollAdmin.js

    该js脚本用来向ca-服务器注册管理员

    'use strict';
    
    //向ca服务器注册管理员
    const FabricCAServices = require('fabric-ca-client');
    const { FileSystemWallet, X509WalletMixin } = require('fabric-network');
    const fs = require('fs');
    const path = require('path');
    
    //connection.json这个文件可以在basic-network文件夹找到,配置了一些连接的信息
    const ccpPath = path.resolve(__dirname, '..', '..', 'basic-network', 'connection.json');
    const ccpJSON = fs.readFileSync(ccpPath, 'utf8');
    const ccp = JSON.parse(ccpJSON);
    
    async function main() {
        try {
    
            // 创建一个CA客户端
            const caURL = ccp.certificateAuthorities['ca.example.com'].url;
            const ca = new FabricCAServices(caURL);
    
            // 创建一个wallet文件夹,用于管理身份.
            const walletPath = path.join(process.cwd(), 'wallet');
            const wallet = new FileSystemWallet(walletPath);
            console.log(`Wallet path: ${walletPath}`);
    
            // 检查是否已经注册管理员.
            const adminExists = await wallet.exists('admin');
            if (adminExists) {
                console.log('An identity for the admin user "admin" already exists in the wallet');
                return;
            }
    
            // 向ca服务器注册管理员,并将从服务器获得的身份证书导入到wallet.
            const enrollment = await ca.enroll({ enrollmentID: 'admin', enrollmentSecret: 'adminpw' });
            const identity = X509WalletMixin.createIdentity('Org1MSP', enrollment.certificate, enrollment.key.toBytes());
            wallet.import('admin', identity);
            console.log('Successfully enrolled admin user "admin" and imported it into the wallet');
    
        } catch (error) {
            console.error(`Failed to enroll admin user "admin": ${error}`);
            process.exit(1);
        }
    }
    
    main();
    
    

    8 创建registerUser.js

    该js脚本用来向fabric-ca服务器注册普通用户

    
    'use strict';
    
    //注册普通用户
    const { FileSystemWallet, Gateway, X509WalletMixin } = require('fabric-network');
    const fs = require('fs');
    const path = require('path');
    
    const ccpPath = path.resolve(__dirname, '..', '..', 'basic-network', 'connection.json');
    const ccpJSON = fs.readFileSync(ccpPath, 'utf8');
    const ccp = JSON.parse(ccpJSON);
    
    async function main() {
        try {
    
            // 创建wallet文件夹用于管理身份信息.
            const walletPath = path.join(process.cwd(), 'wallet');
            const wallet = new FileSystemWallet(walletPath);
            console.log(`Wallet path: ${walletPath}`);
    
            // 检查是否已经注册过user1用户
            const userExists = await wallet.exists('user1');
            if (userExists) {
                console.log('An identity for the user "user1" already exists in the wallet');
                return;
            }
    
            // 检查是否已经注册了admin用户
            const adminExists = await wallet.exists('admin');
            if (!adminExists) {
                console.log('An identity for the admin user "admin" does not exist in the wallet');
                console.log('Run the enrollAdmin.js application before retrying');
                return;
            }
    
            // 创建一个用于连接peer节点的网关
            const gateway = new Gateway();
            await gateway.connect(ccp, { wallet, identity: 'admin', discovery: { enabled: false } });
    
            // 创建一个用于与ca 服务器交互的ca 客户端对象
            const ca = gateway.getClient().getCertificateAuthority();
            const adminIdentity = gateway.getCurrentIdentity();
    
            // 注册用户到ca服务器,并将从ca服务器获得的身份信息导入到wallet文件夹.
            const secret = await ca.register({ affiliation: 'org1.department1', enrollmentID: 'user1', role: 'client' }, adminIdentity);
            const enrollment = await ca.enroll({ enrollmentID: 'user1', enrollmentSecret: secret });
            const userIdentity = X509WalletMixin.createIdentity('Org1MSP', enrollment.certificate, enrollment.key.toBytes());
            wallet.import('user1', userIdentity);
            console.log('Successfully registered and enrolled admin user "user1" and imported it into the wallet');
    
        } catch (error) {
            console.error(`Failed to register user "user1": ${error}`);
            process.exit(1);
        }
    }
    
    main();
    
    

    9 创建query.js

    该js脚本用来查询汽车信息

    
    
    'use strict';
    
    //通过链码查询
    const { FileSystemWallet, Gateway } = require('fabric-network');
    const fs = require('fs');
    const path = require('path');
    
    const ccpPath = path.resolve(__dirname, '..', '..', 'basic-network', 'connection.json');
    const ccpJSON = fs.readFileSync(ccpPath, 'utf8');
    const ccp = JSON.parse(ccpJSON);
    
    async function main() {
        try {
    
            // 创建一个用于管理身份的文件夹wallet
            const walletPath = path.join(process.cwd(), 'wallet');
            const wallet = new FileSystemWallet(walletPath);
            console.log(`Wallet path: ${walletPath}`);
    
            // 检查是否已经注册好普通用户user1
            const userExists = await wallet.exists('user1');
            if (!userExists) {
                console.log('An identity for the user "user1" does not exist in the wallet');
                console.log('Run the registerUser.js application before retrying');
                return;
            }
    
            // 创建一个用于与peer节点通信的网关对象
            const gateway = new Gateway();
            await gateway.connect(ccp, { wallet, identity: 'user1', discovery: { enabled: false } });
    
            // 获得我们的链码部署到的channel对象
            const network = await gateway.getNetwork('mychannel');
    
            // 通过链码名称获得智能合约对象
            const contract = network.getContract('fabcar');
    
            // 执行指定的交易.
            // queryCar 交易 - 需要1个参数, 例如: ('queryCar', 'CAR4')
            // queryAllCars 交易 - 不需要任何参数, 例如: ('queryAllCars')
            //注意,如果不修改状态使用evaluateTransaction
            const result = await contract.evaluateTransaction('queryAllCars');
            console.log(`Transaction has been evaluated, result is: ${result.toString()}`);
    
        } catch (error) {
            console.error(`Failed to evaluate transaction: ${error}`);
            process.exit(1);
        }
    }
    
    main();
    
    
    

    10 创建invoke.js

    该js脚本做invoke调用

    'use strict';
    
    //调用链码对应的函数
    const { FileSystemWallet, Gateway } = require('fabric-network');
    const fs = require('fs');
    const path = require('path');
    
    const ccpPath = path.resolve(__dirname, '..', '..', 'basic-network', 'connection.json');
    const ccpJSON = fs.readFileSync(ccpPath, 'utf8');
    const ccp = JSON.parse(ccpJSON);
    
    async function main() {
        try {
    
            // 创建一个用于管理身份的文件夹wallet
            const walletPath = path.join(process.cwd(), 'wallet');
            const wallet = new FileSystemWallet(walletPath);
            console.log(`Wallet path: ${walletPath}`);
    
           // 检查是否已经注册好普通用户user1
            const userExists = await wallet.exists('user1');
            if (!userExists) {
                console.log('An identity for the user "user1" does not exist in the wallet');
                console.log('Run the registerUser.js application before retrying');
                return;
            }
    
          // 创建一个用于与peer节点通信的网关对象
            const gateway = new Gateway();
            await gateway.connect(ccp, { wallet, identity: 'user1', discovery: { enabled: false } });
    
             // 获得我们的链码部署到的channel对象
            const network = await gateway.getNetwork('mychannel');
    
            // 创建一个用于与peer节点通信的网关对象
            const contract = network.getContract('fabcar');
    
            // 提交特定的交易 .
            // createCar 交易 - 需要5个参数, 例如: ('createCar', 'CAR12', 'Honda', 'Accord', 'Black', 'Tom')
            // changeCarOwner 交易 - 需要2个参数 , 例如: ('changeCarOwner', 'CAR10', 'Dave')
            //注意,涉及到修改状态使用submitTransaction
            await contract.submitTransaction('createCar', 'CAR12', 'Honda', 'Accord', 'Black', 'Tom');
            console.log('Transaction has been submitted');
    
            // 断开网关连接
            await gateway.disconnect();
    
        } catch (error) {
            console.error(`Failed to submit transaction: ${error}`);
            process.exit(1);
        }
    }
    
    main();
    
    

    11 启动网络

    生成证书(注,只需要执行一次就ok了,以后都不用执行这一步了

    $ ./generate.sh
    

    先停止到旧的网络

    
    $ docker stop -f $(docker ps -aq)
    $ docker rm -f $(docker ps -aq)
    $ docker rmi -f $(docker images | grep fabcar | awk '{print $3}')
    

    然后启动网络,该脚本只启动了ca、orderer、peer、couchDb这几个容器,没有启动cli容器。并且创建名字为mychannel的通道,随后还让peer0.Org1加入了该通道

    $ rm -rf ./hfc-key-store
    $ cd basic-network
    $ ./start.sh
    

    12 启动cli容器

    $ docker-compose -f ./docker-compose.yml up -d cli
    

    13 安装和实例化链码

    打开一个新的终端,不用进入cli容器,可以在外边执行,用-exec表示在外边执行

    安装链码

    $ docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode install -n fabcar -v 1.0 -p github.com/fabcar/go -l golang
    

    实例化链码

    $ docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode instantiate -o orderer.example.com:7050 -C mychannel -n fabcar -l golang -v 1.0 -c '{"Args":[]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
    
    

    调用initLedger函数初始化账本

    $ docker exec -e "CORE_PEER_LOCALMSPID=Org1MSP" -e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp" cli peer chaincode invoke -o orderer.example.com:7050 -C mychannel -n fabcar -c '{"function":"initLedger","Args":[]}'
    

    14 进入app1目录安装依赖

    到了这一步,证书已经生成,节点网络已经启动,链码也安装和实例化好了,接下来就来测试一下sdk的调用是否成功了。

    进入app1目录,并执行npm install安装依赖模块

    $ cd app1
    $ npm install
    

    15 注册管理员

    $ node enrollAdmin.js
    

    输出如下信息

    Store path:/home/bob/go/src/github.com/fabric-study/sdk-node-study1/app1/hfc-key-store
    Successfully enrolled admin user "admin"
    Assigned the admin user to the fabric client ::{"name":"admin","mspid":"Org1MSP","roles":null,"affiliation":"","enrollmentSecret":"","enrollment":{"signingIdentity":"607d571669d90da409ebdaec5855e3a395bbf7af5aab200cd5a902a4054c9cb0","identity":{"certificate":"-----BEGIN CERTIFICATE-----\nMIICAjCCAaigAwIBAgIUGuRlUgmDVeRPKDsf67/6fom2bvMwCgYIKoZIzj0EAwIw\nczELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT\nE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTkwMzIyMDY0NjAwWhcNMjAwMzIxMDY1\nMTAwWjAhMQ8wDQYDVQQLEwZjbGllbnQxDjAMBgNVBAMTBWFkbWluMFkwEwYHKoZI\nzj0CAQYIKoZIzj0DAQcDQgAE4UAK/Z9BFZE7Fji6S4KTTY/2DGK6Vz0FtuhOQStE\n0rQ5PfwcbUEYFP/Z1m3Lhtvkly09eFWM+vibivprOQAbzaNsMGowDgYDVR0PAQH/\nBAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFFja6ma5kc1yk5ax5h0Fc0zl\niI3XMCsGA1UdIwQkMCKAIEI5qg3NdtruuLoM2nAYUdFFBNMarRst3dusalc2Xkl8\nMAoGCCqGSM49BAMCA0gAMEUCIQDr6unOLXftqasK83fkthyfykHNI4Mt7y7DA+lX\ns2PyHQIgS54OqyzJ0kulh/xyHd9IkDRAM2iJPVsxCzMUP+t/C1s=\n-----END CERTIFICATE-----\n"}}}
    

    16 注册普通用户

    $ node register.js
    

    输出如下信息

     Store path:/home/bob/go/src/github.com/fabric-study/sdk-node-study1/app1/hfc-key-store
    Successfully loaded admin from persistence
    Successfully registered user1 - secret:OhvdSyIJrqqM
    Successfully enrolled member user "user1" 
    User1 was successfully registered and enrolled and is ready to interact with the fabric network
    

    17 执行查询

    $ node query.js
    

    可以看到,所有的汽车被查出来

    Query has completed, checking results
    Response is  [{"Key":"CAR0", "Record":{"colour":"blue","make":"Toyota","model":"Prius","owner":"Tomoko"}},{"Key":"CAR1", "Record":{"colour":"red","make":"Ford","model":"Mustang","owner":"Brad"}},{"Key":"CAR2", "Record":{"colour":"green","make":"Hyundai","model":"Tucson","owner":"Jin Soo"}},{"Key":"CAR3", "Record":{"colour":"yellow","make":"Volkswagen","model":"Passat","owner":"Max"}},{"Key":"CAR4", "Record":{"colour":"black","make":"Tesla","model":"S","owner":"Adriana"}},{"Key":"CAR5", "Record":{"colour":"purple","make":"Peugeot","model":"205","owner":"Michel"}},{"Key":"CAR6", "Record":{"colour":"white","make":"Chery","model":"S22L","owner":"Aarav"}},{"Key":"CAR7", "Record":{"colour":"violet","make":"Fiat","model":"Punto","owner":"Pari"}},{"Key":"CAR8", "Record":{"colour":"indigo","make":"Tata","model":"Nano","owner":"Valeria"}},{"Key":"CAR9", "Record":{"colour":"brown","make":"Holden","model":"Barina","owner":"Shotaro"}}]
    

    18 执行调用

    $ node invoke.js
    

    相关文章

      网友评论

          本文标题:使用fabric-sdk-node的示例2

          本文链接:https://www.haomeiwen.com/subject/haurvqtx.html