概念补充 hyperleger fabric的三个重要角色
client 客户端,用来发起transaction process(提案),可以是cli、node sdk或者Java sdk
peers 最常见的节点,维护了ledger的副本,记录验证同步数据
orderer 接收背书后的请求,排序生成区块,最后交给peer节点
共识的达成 fabric的共识达成通过三个步骤
客户端发起提案,每个 peer 节点模拟执行,进行背书
orderer 节点进行排序
orderer 节点验证后生成区块交给 peer 节点去 apply 三个步骤保证了区块链数据的一致性和正确性transaction流程 1、sdk发起transaction proposal给peers进行背书(根据背书策略背书) 2、背书节点模拟执行,返回签名的执行结果读写集(RW sets)交还给cli,sdk根据背书策略确定请求是否合法 3、cli收集到读写集后给orderer节点进行线性排序 4、orderer验证、排序、生成区块,再给所有peers进行ledger数据更新 5、peers会验证orderer的读写集与当前世界状态是否一致来更新ledger,世界状态也随之变化 6、最后sdk收到peers世界状态改变后的返还信息确认账本更新完成orderer节点 解决双花问题(把并行事件线性排序) hyperledger的orderer类似中心机构出票的机制,所以效率很高没有挖矿的概念(为什么不挖矿1#14:00)(orderer节点防挂1#16:50)排序机制 solo 单一 orderer 节点用的玩具级别的排序服务,单一 orderer 服务器.采用 solo 方式kafka 卡夫卡是阿帕奇的开源流式消息处理服务平台.提供非拜占庭错误(故障错误)的容错性即挂掉的排序节点不会返回误导性数据SBFT 简单拜占庭容错,容忍集群中的 orderer 节点有不超过1/3的错误channels 通道相当于hyperledger的子网络,不同channels相互独立,可拥有不同的sdk/ledger/peers orderer可以看到所有channel的数据state db世界状态数据库 世界状态被存储在状态数据库里面。chaincode执行后stub.putState(key, Bufer.from(value))这些信息都是被以 key,value 的形式存放到状态数据库中通过 stub.getState(key) 的方式读出来。 hyperledger fabric 支持两种模式的状态数据库:
levelDB 文件形式存储,不易查看管理.
couchDB 支持福查询,独立的容器数据库智能合约 补充chaincode就是商业逻辑,任何更新账本的操作都智能通过智能合约来完成MSP(管理服务提供商) 使用CA来颁发证书进行认证,默认fabric-ca api
实战(nodejs) 定义资产结构json 以下伪代码变量名直接使用中文
1 2 3 4 5 6 7 8 9 10 11 12 var 一次成绩 = { 学生姓名: " " , 学生学号uuid: " " , 考试科目: " " , 考试号uuid:" " , 信息修改者(即阅卷人):" " , 阅卷者uuid:"" , 卷面总成绩: "0" , 卷面详细成绩1:"0" , 卷面详细成绩2:"0" , 卷面详细成绩3:"0" }
之类
创建基本智能合约框架 1 2 3 4 5 6 7 8 9 10 11 'use strict'; const shim = require (' fabric-shim '); const util = require ('util'); const Chaincode = class{ async Init (stub) { console.info ('Instantiated chaincode'); return shim.success (); } shim.start( new Chaincode ()); }
invoke(调用)函数 即如何调用函数的异常处理机制
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 async Invoke (stub){ let ret = stub.getFunctionAndParameters(); console.info( ret ); let method = this [ ret.fcn ]; if (! method ){ console.error('找不到要调用的函数,函数名:’+ ret.fcn); throw new Error('找不到要调用的函数,函数名:’+ ret.fcn); } fry { let payload = await method ( stub ,ret.params ); return shim.success (payload ); } catch (err){ console . log(err); return shim.error(err); } }
具体业务函数 如:查找
1 2 3 4 5 6 7 8 9 10 11 12 13 async query(stub,args){ if (args.length!=1){ throw new Error('错误调用参数'); } let number = args[0 ]; let asBytes = await stub.getState(number); if (!asBytes || asBytes.toString().length<=0 ){ throw new Error(asBytes + '不存在'); } console.log(asBytes.toString()); return asBytes; }
初始化账本initledger(单独写具体的init)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 async initLedger(stub,args){ console.info('开始初始化账本'); let grdes=[]; grades.push({ 学生姓名: "A" , 考试科目: "123" , 卷面总成绩: "0" }); grades.push({ 学生姓名: "B" , 考试科目: "456" , 卷面总成绩: "0" }); for (let i = 0 ;i < grdes.lenth;i++){ await stub.putState('GRADE' + i,Buffer.from(JSON.stringify(grades[i]))); console.info('添加',grades[i]); } console.info('结束初始化'); }
记录
1 2 3 4 5 6 7 8 9 10 11 12 13 14 async recordGrade(stub,args){ console.info('开始记录'); if (args.length !=4){ throw new Error('需要四个参数:ID,学生姓名,考试科目,卷面总成绩‘); } var grade = { 学生姓名: args[1 ], 考试科目: args[2 ], 卷面总成绩: args[3 ] }; await stub.putState(args[0 ],Buffer.from(JSON.stringify(grade))); console.info('记录成功'); }
查看所有: 修改: