夏天de毛裤 夏天de毛裤
关注数: 0 粉丝数: 88 发帖数: 992 关注贴吧数: 63
Go语言未来应用前景如何,好不好找工作?   个人觉得,前景很乐观。未来掌握该语言的工作也会越来越多,具体工作好不好找还要看自己技术掌握程度。   应用前景好。Go语言是谷歌2009发布的第二款开源编程语言。是一个相对而言比较新的编程语言,虽然Go尚未成熟,但谷歌旗下AppEngine和其他部分产品已经开始使用go语言来编写。正因如此,谷歌才需要外部编程人员的协助。派克说:我们需要更好的程序库和工具,而开源社区能够在这些方面为我们提供很大的帮助。   很多人喜欢Go语言,因为Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。此外,不得不承认,简洁、快速、安全、并行、有趣、源,内存管理、数组安全、编译迅速等特色都使得Go语言更加吸引人。   工作效率很重要,相当于时间和金钱。Go语言有很高的生产效率。Go不需要build文件(Makefile,Java的build.xml,pom.xml这些),而是只需要执行"gobuild"即可,通过目录结构自己找到项目结构。通过这样的“约定优于配置”(conventionoverconfiguration)的设计,大大提高了效率。调用C代码的cgo的设计,而在Go这里简单到可以把C代码直接嵌到Go代码同一个文件里,然后"gobuild"就可以。   综上,虽然Go语言比较新,但其特色跟优点还是很明显的,未来前景很看好,熟练掌握Go语言能节省许多时间,提高工作效率,未来找工作就不用担心。   一,google的强力支持。go刚开始时实际上属于一个玩票性质的项目,但是后面发展越来越好,上升成了公司的项目。   二,开发团队。go的开发者都是大神,RobPike,KenThompson(c语言,unix开发者)和RobertGriesemer,都是牛逼哄哄的人物。   三,明星产品的出现。docker的出现,完美的证明了go的实力。   四,go自身的魅力。良好的工程支持,简洁的语法,优秀的跨平台能力,接近c语言的性能。 所以,go是很有前景的语言,特别是在服务端开发方面。据我所知,滴滴、bilibili、360、腾讯、京东都在使用go,还有很多游戏公司也在用go做游戏服务器。 兄弟连Go全栈与区块链课程共计22周学习时长,划分为9个学习阶段,即区块链主流语言-Go语言开发实战 、区块链后端技术体系-Go语言高并发和服务器开发、Go开发区块链公链(区块链密码学、分布式编程、共识算法、基本概念,Golan公链开发)、以-太坊与智能合约与DAPP开发、区块链分布式应用开发、区块链系统框架开发-超级账本与区块链3.0EOS 、Go与区块链面试强化和高级企业级项目实战。 整个课程体系将企业招聘区块链相关岗位时最为关注的区块链开发语言-Go语言、密码学、加密共识算法及区块链开源开发经验等内容涵盖其中,课程内容由浅入深,循序渐进。
分享新手如何做SEO优化?   随着互联网+时代的来临,传统的营销模式正在慢慢退出舞台,更多的企业将网络营销作为整体营销战略的重中之重,网络营销人才自然不可或缺。而与此同时电商平台的日益壮大,也让网络营销人才炙手可热。更多的人投身到网络营销行业之中,SEO工程师、SEM优化师、新媒体推广运营策划、电商运营等职位已经成为高薪的代名词。 SEO是近年来网络营销中最火的职位,那么初入行者要怎样才能做好优化呢?又怎样做到有效优化呢?SEO优化的真正的做法就是通过对网站的代码、站内、站外的系统调整,使网站对搜索引擎更加的友好,适应搜索引擎的排名规则,从而达到一个理想的关键词排名。 1、关键词的分析   整个SEO流程都是围绕关键词展开的,所以网站的SEO优化效果的好坏与关键词是有绝对的关系。关键词分析包括(目标关键词、长尾关键词、营销性关键词、热搜关键词、相关关键词)等等。 2、代码优化   网站的版面、显示的效果,都是与代码息息相关的。代码是否简洁、清楚,对企业网站的排名有非常大的影响。 3、网站内部优化   网站关键词的分布与网站内部链接的都建设都是属于站内优化,当然这一步也能直接影响到网站关键词的排名。网站的首页、频道页、栏目页、单页、内容页关键词的布局都是非常重要的,不同的页面权重都不一样,所以关键词的分布就得看SEO的实施策略。 4网站外部推广   网站除了很好的内部结构之外,还离不开外链的支持。目前很多网站排名非常稳定,与强大的外链资源是有密切关系的。具体细分:高质量的链接、友情链接、单向链接、软文链接、甚至一些群发的痕迹等等..如:博客文章带链接,博客友情链接,软文链接(提交文章),论坛发贴带链接,论坛签名带链接,留言本和评论带链接,提交书签、目录、搜索引擎….
学习Python编程有哪些细节是需要注意的? Python作为一种面向对象的解释型计算机程序设计语言,相较于其他主流编程语言,Python的可读性更强,以此学习这门语言也更容易上手,非常适合初学者来学。但是,简单也并不意味着人人都能将它学好,所谓细节决定成败,就和大家讲解下学习Python编程这些细节你需要注意。 1、空格。不要因为空格不是Python语法的必需部分,就忽视它的作用,在函数之间或类的办法之间坚持用空行分隔,可以使得我们写的代码更加清晰明了,也十分有利于后期的代码保护或重构。 2、源代码。Python是开放源码软件之一。使用者可以自由地发布这个软件的拷贝、阅读它的源代码、对它做改动、把它的一部分用于新的自由软件中。所以你要经常去看一些好的源代码,不仅能提升你的能力还能协助你更好的去学习。 3、注释。注释不仅能使看见你代码的人容易理解,也能让你更好的定位代码函数,即使上半年前写的代码只要你在之前加有注释,你也能快速知道你写的代码是什么意思,长久养成注释的习惯可以大大提高你的工作效率。 4、缩进。在Python编程中缩进显得十分重要,在Python的代码块中必须运用相同数目的行首缩进空格数,否则会形成脚本运行错误,提示你格局不正确之类的信息。 5、编程思维。良好的编程思维是学好编程语言的基础和先决条件,如果你想学好Python,那么平时注重培养自己的编程思想就显得尤为重要。 市场上从事Python开发的人员薪资待遇很是可观,成为一名Python开发的人员无疑为自己的就业解决了实质性的问题。
Java初学者如何学好Java编程 Java作为一门盛行于世的编程语言,Java一直很受人们的欢迎,学Java的朋友一直是日渐增加的,能被称的上Java初学者的朋友特别的多,但是真正摆脱Java初学者称号的朋友又有多少呢?Java初学者如何学好Java编程?这就是今天小编想要跟你一起分享的。 1.不畏惧Java编程   很多朋友在还没学Java之前,总是在问Java编程难不难学,还没开始学就很担心Java编程难学,听到其他人说难学,无疑会产生畏惧的心理,有的Java初学者才刚刚看了一点点Java知识,就觉得自己学不会,然后就不太想学Java编程了,这种情况在Java初学者身上是屡见不鲜,要想学好Java编程,首先要不畏惧Java编程。 2.做好Java编程模仿学习   对于Java初学者来说,刚刚接触Java编程,很多的时候都是处于好奇的状态当中,比如这个Java知识点原理为什么是这样的,这个Java代码编写为什么是这样的,很多时候看到Java代码比起跟着敲写,更多的是关注它的理论,学Java编程最重要的就是做好模仿工作,即刚开始学Java编程就老老实实根据示范的例子,自己多多操作几遍。 3.找个专业的Java老师带你入门   我们都知道,Java的学习是入学门槛低,但是真正能够顺利Java入门的朋友却不多,入门Java也只是进入Java行业的一小步,但也是相当关键的一步。如果想要在Java行业中顺利找到满意的工作,站住脚跟,你需要更加深入的理解、学习。然而,这对于Java初学者来说很难,只有专业的指导和引领,才能更好的踏入Java编程的大门,这时候就得找个专业的Java老师带你入门。
UI网页设计应该注意的细节   一个网页是否吸引人,除了网站提供的内容资料外,网页的设计也是很重要的影响因素。作为一名UI网页设计师,对于网页设计,一定要有自己的想法,一个好看的网页一定是图片和文字比例协调的,在为网页搭配图片的时候,提示:有几个需要注意的细节。 1、构图   图片摆放的位置就和它的内容一样重要。每个独立的部分需要彼此平衡一致,从而构成有感觉的整体。图片经常用来强调或是阐明某个内容。 2、网页头部和大背景   背景大图一般是指一张较大尺寸的处于页头附近的摄影或插图。它常常会给予在者关于网站的最直观的印象,体现网站内容的潜在含义。大图和标题首先应当能够做到对现有内容的延伸和拓展。如果网页的布局有些令人迷惑,你需要利用图片做出适当的补充。 3、照片及后期处理   练习摄影之外,你的PS技术也会有所长进。Photoshop是最强大的图片编辑软件你可以将图片加工成任何你能想到的样子。首先要学习的是如何将物体从背景中抠出来。当你需要在你的页面中加入一个人物或物体,这项技能很有用。 UI网页设计师的学习途径除了UI设计培训课程之外,还有网上丰富的资源,你可以参考借鉴他人的网页设计,以此激发自己的创意想法。当然了,UI设计基础是最重要的,在此基础上,在进行灵感和想法的碰撞。
兄弟连区块链教程区块链背后的信息安全2DES、3DES加密算法原理二 ## Feistel轮函数 每次Feistel轮函数内部,均经过4种运算,即: * 1、扩展置换:右侧32位做扩展置换,扩展置换将32位输入扩展成为48位输出,使得扩展后输出数据长度与48位子密钥等长。 * 2、异或运算:右侧32位扩展置换为48位后,与48位子密钥做异或运算。 * 3、S盒置换:将异或运算后的48位结果,分成8个6位的块,每块通过S盒置换产生4位的输出,8个块S盒置换后组成32位的输出。 S盒置换的过程为:6位中取第1位和第6位组成行号,剩余第2、3、4、5位组成列号,从S盒置换表中取出相应行、列的十进制数,并转化为4位二进制数,即为S盒输出。 * 4、P盒置换:S盒置换后的32位输出数据,进行P盒置换,仍然输出为32位数据。 go标准库中DES Feistel轮函数代码如下: ```go func feistel(right uint32, key uint64) (result uint32) { //右侧32位扩展置换为48位,并与48位子密钥做异或运算 sBoxLocations := key ^ expandBlock(right) var sBoxResult uint32 for i := uint8(0); i < 8; i++ { //sBoxLocations>>42、sBoxLocations <<= 6,按每6位分块 sBoxLocation := uint8(sBoxLocations>>42) & 0x3f sBoxLocations <<= 6 //6位中取第1位和第6位组成行号 row := (sBoxLocation & 0x1) | ((sBoxLocation & 0x20) >> 4) //剩余第2、3、4、5位组成列号 column := (sBoxLocation >> 1) & 0xf //feistelBox包括了S盒置换和P盒置换的实现 sBoxResult ^= feistelBox[i][16*row+column] } return sBoxResult } var feistelBox [8][64]uint32 //P盒置换 func permuteBlock(src uint64, permutation []uint8) (block uint64) { for position, n := range permutation { bit := (src >> n) & 1 block |= bit << uint((len(permutation)-1)-position) } return } //初始化feistelBox func init() { for s := range sBoxes { for i := 0; i < 4; i++ { for j := 0; j < 16; j++ { f := uint64(sBoxes[s][i][j]) << (4 * (7 - uint(s))) f = permuteBlock(f, permutationFunction[:]) feistelBox[s][16*i+j] = uint32(f) } } } } //代码位置src/crypto/des/block.go ``` 附go标准库中使用的扩展置换表和P盒置换表: ```go //扩展置换表 var expansionFunction = [48]byte{ 0, 31, 30, 29, 28, 27, 28, 27, 26, 25, 24, 23, 24, 23, 22, 21, 20, 19, 20, 19, 18, 17, 16, 15, 16, 15, 14, 13, 12, 11, 12, 11, 10, 9, 8, 7, 8, 7, 6, 5, 4, 3, 4, 3, 2, 1, 0, 31, } //P盒置换表 var permutationFunction = [32]byte{ 16, 25, 12, 11, 3, 20, 4, 15, 31, 17, 9, 6, 27, 14, 1, 22, 30, 24, 8, 18, 0, 5, 29, 23, 13, 19, 2, 26, 10, 21, 28, 7, } //代码位置src/crypto/des/const.go ``` 附go标准库中使用的S盒置换表: ```go var sBoxes = [8][4][16]uint8{ // S-box 1 { {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7}, {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8}, {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0}, {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13}, }, // S-box 2 { {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10}, {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5}, {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15}, {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9}, }, // S-box 3 { {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8}, {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1}, {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7}, {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12}, }, // S-box 4 { {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15}, {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9}, {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4}, {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14}, }, // S-box 5 { {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9}, {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6}, {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14}, {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3}, }, // S-box 6 { {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11}, {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8}, {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6}, {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13}, }, // S-box 7 { {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1}, {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6}, {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2}, {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12}, }, // S-box 8 { {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7}, {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2}, {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8}, {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11}, }, } //代码位置src/crypto/des/const.go ``` ## 3DES DES是一个经典的对称加密算法,但也缺陷明显,即56位的密钥安全性不足,已被证实可以在短时间内破解。 为解决此问题,出现了3DES,也称Triple DES,3DES为DES向AES过渡的加密算法,它使用3条56位的密钥对数据进行三次加密。 为了兼容普通的DES,3DES并没有直接使用加密->加密->加密的方式,而是采用了加密->解密->加密的方式。 当三重密钥均相同时,前两步相互抵消,相当于仅实现了一次加密,因此可实现对普通DES加密算法的兼容。 3DES解密过程,与加密过程相反,即逆序使用密钥。 go标准中3DES加密算法的实现如下: ```go type tripleDESCipher struct { cipher1, cipher2, cipher3 desCipher } func NewTripleDESCipher(key []byte) (cipher.Block, error) { if len(key) != 24 { return nil, KeySizeError(len(key)) } c := new(tripleDESCipher) c.cipher1.generateSubkeys(key[:8]) c.cipher2.generateSubkeys(key[8:16]) c.cipher3.generateSubkeys(key[16:]) return c, nil } //3DES加密 func (c *tripleDESCipher) Encrypt(dst, src []byte) { c.cipher1.Encrypt(dst, src) c.cipher2.Decrypt(dst, dst) c.cipher3.Encrypt(dst, dst) } //3DES解密 func (c *tripleDESCipher) Decrypt(dst, src []byte) { c.cipher3.Decrypt(dst, src) c.cipher2.Encrypt(dst, dst) c.cipher1.Decrypt(dst, dst) } //代码位置src/crypto/des/cipher.go ``` ## 后记 相比DES,3DES因密钥长度变长,安全性有所提高,但其处理速度不高。 因此又出现了AES加密算法,AES较于3DES速度更快、安全性更高,后续单独总结。 感谢关注兄弟连区块链教程分享!
兄弟连区块链教程区块链背后的信息安全2DES、3DES加密算法原理一   兄弟连区块链教程区块链背后的信息安全2DES、3DES加密算法原理一,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。 # DES、3DES加密算法原理及其GO语言实现 DES加密算法,为对称加密算法中的一种。70年代初由IBM研发,后1977年被美国国家标准局采纳为数据加密标准,即DES全称的由来:Data Encryption Standard。 对称加密算法,是相对于非对称加密算法而言的。两者区别在于,对称加密在加密和解密时使用同一密钥,而非对称加密在加密和解密时使用不同的密钥,即公钥和私钥。 常见的DES、3DES、AES均为对称加密算法,而RSA、椭圆曲线加密算法,均为非对称加密算法。 DES是以64比特的明文为一个单位来进行加密的,超过64比特的数据,要求按固定的64比特的大小分组,分组有很多模式,后续单独总结,暂时先介绍DES加密算法。 DES使用的密钥长度为64比特,但由于每隔7个比特设置一个奇偶校验位,因此其密钥长度实际为56比特。奇偶校验为最简单的错误检测码,即根据一组二进制代码中1的个数是奇数或偶数来检测错误。 ## Feistel网络 DES的基本结构,由IBM公司的Horst Feistel设计,因此称Feistel网络。 在Feistel网络中,加密的每个步骤称为轮,经过初始置换后的64位明文,进行了16轮Feistel轮的加密过程,最后经过终结置换后形成最终的64位密文。 64比特明文被分为左、右两部分处理,右侧数据和子密钥经过轮函数f生成用于加密左侧数据的比特序列,与左侧数据异或运算,运算结果输出为加密后的左侧,右侧数据则直接输出为右侧。 其中子密钥为本轮加密使用的密钥,每次Feistel均使用不同的子密钥。子密钥的计算,以及轮函数的细节,稍后下文介绍。 由于一次Feistel轮并不会加密右侧,因此需要将上一轮输出后的左右两侧对调后,重复Feistel轮的过程,DES算法共计进行16次Feistel轮,最后一轮输出后左右两侧无需对调。 DES加密和解密的过程一致,均使用Feistel网络实现,区别仅在于解密时,密文作为输入,并逆序使用子密钥。 go标准库中DES算法实现如下: ```go func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) { b := binary.BigEndian.Uint64(src) //初始置换 b = permuteInitialBlock(b) left, right := uint32(b>>32), uint32(b) var subkey uint64 //共计16次feistel轮 for i := 0; i < 16; i++ { //加密和解密使用子密钥顺序相反 if decrypt { subkey = subkeys[15-i] } else { subkey = subkeys[i] } //feistel轮函数 left, right = right, left^feistel(right, subkey) } //最后一轮无需对调 preOutput := (uint64(right) << 32) | uint64(left) //终结置换 binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput)) } //代码位置src/crypto/des/block.go ``` ## 初始置换和终结置换 进入Feistel轮之前,64位明文需做一次初始置换。Feistel轮结束后,需做一次反向操作,即终结置换。 初始置换和终结置换目的是为加强硬件的破解难度而加的。 附go标准库中使用的初始置换表和终结置换表如下: ```go //初始置换表 var initialPermutation = [64]byte{ 6, 14, 22, 30, 38, 46, 54, 62, 4, 12, 20, 28, 36, 44, 52, 60, 2, 10, 18, 26, 34, 42, 50, 58, 0, 8, 16, 24, 32, 40, 48, 56, 7, 15, 23, 31, 39, 47, 55, 63, 5, 13, 21, 29, 37, 45, 53, 61, 3, 11, 19, 27, 35, 43, 51, 59, 1, 9, 17, 25, 33, 41, 49, 57, } //终结置换表 var finalPermutation = [64]byte{ 24, 56, 16, 48, 8, 40, 0, 32, 25, 57, 17, 49, 9, 41, 1, 33, 26, 58, 18, 50, 10, 42, 2, 34, 27, 59, 19, 51, 11, 43, 3, 35, 28, 60, 20, 52, 12, 44, 4, 36, 29, 61, 21, 53, 13, 45, 5, 37, 30, 62, 22, 54, 14, 46, 6, 38, 31, 63, 23, 55, 15, 47, 7, 39, } //代码位置src/crypto/des/const.go ``` ## 子密钥的计算 DES初始密钥为64位,其中8位用于奇偶校验,实际密钥为56位,64位初始密钥经过PC-1密钥置换后,生成56位串。 经PC-1置换后56位的串,分为左右两部分,各28位,分别左移1位,形成C0和D0,C0和D0合并成56位,经PC-2置换后生成48位子密钥K0。 C0和D0分别左移1位,形成C1和D1,C1和D1合并成56位,经PC-2置换后生成子密钥K1。 以此类推,直至生成子密钥K15。但注意每轮循环左移的位数,有如下规定: ```go var ksRotations = [16]uint8{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1} //代码位置src/crypto/des/const.go ``` go标准库中DES子密钥计算的代码如下: ```go func (c *desCipher) generateSubkeys(keyBytes []byte) { key := binary.BigEndian.Uint64(keyBytes) //PC-1密钥置换,生成56位串 permutedKey := permuteBlock(key, permutedChoice1[:]) //56位串分左右两部分,各28位,ksRotate为依次循环左移1位 leftRotations := ksRotate(uint32(permutedKey >> 28)) rightRotations := ksRotate(uint32(permutedKey<<4) >> 4) //生成子密钥 for i := 0; i < 16; i++ { //合并左右两部分,之后PC-2置换 pc2Input := uint64(leftRotations[i])<<28 | uint64(rightRotations[i]) c.subkeys[i] = permuteBlock(pc2Input, permutedChoice2[:]) } } //代码位置src/crypto/des/block.go ``` 附go标准库中使用的PC-1置换表和PC-2置换表: ```go //PC-1置换表 var permutedChoice1 = [56]byte{ 7, 15, 23, 31, 39, 47, 55, 63, 6, 14, 22, 30, 38, 46, 54, 62, 5, 13, 21, 29, 37, 45, 53, 61, 4, 12, 20, 28, 1, 9, 17, 25, 33, 41, 49, 57, 2, 10, 18, 26, 34, 42, 50, 58, 3, 11, 19, 27, 35, 43, 51, 59, 36, 44, 52, 60, } //PC-2置换表 var permutedChoice2 = [48]byte{ 42, 39, 45, 32, 55, 51, 53, 28, 41, 50, 35, 46, 33, 37, 44, 52, 30, 48, 40, 49, 29, 36, 43, 54, 15, 4, 25, 19, 9, 1, 26, 16, 5, 11, 23, 8, 12, 7, 17, 0, 22, 3, 10, 14, 6, 20, 27, 24, } //代码位置src/crypto/des/const.go ``` 未完待续感谢关注兄弟连区块链教程分享!
兄弟连区块链教程区块链信息安全3椭圆曲线加解密及签名算法二   兄弟连区块链教程区块链信息安全3椭圆曲线加解密及签名算法的技术原理二。 # 椭圆曲线加解密及签名算法的技术原理及其Go语言实现 ### 椭圆曲线加解密算法原理 建立基于椭圆曲线的加密机制,需要找到类似RSA质因子分解或其他求离散对数这样的难题。 而椭圆曲线上的已知G和xG求x,是非常困难的,此即为椭圆曲线上的的离散对数问题。 此处x即为私钥,xG即为公钥。 椭圆曲线加密算法原理如下: 设私钥、公钥分别为k、K,即K = kG,其中G为G点。 公钥加密: 选择随机数r,将消息M生成密文C,该密文是一个点对,即: C = {rG, M+rK},其中K为公钥 私钥解密: M + rK - k(rG) = M + r(kG) - k(rG) = M 其中k、K分别为私钥、公钥。 ### 椭圆曲线签名算法原理 椭圆曲线签名算法,即ECDSA。 设私钥、公钥分别为k、K,即K = kG,其中G为G点。 私钥签名: * 1、选择随机数r,计算点rG(x, y)。 * 2、根据随机数r、消息M的哈希h、私钥k,计算s = (h + kx)/r。 * 3、将消息M、和签名{rG, s}发给接收方。 公钥验证签名: * 1、接收方收到消息M、以及签名{rG=(x,y), s}。 * 2、根据消息求哈希h。 * 3、使用发送方公钥K计算:hG/s + xK/s,并与rG比较,如相等即验签成功。 原理如下: hG/s + xK/s = hG/s + x(kG)/s = (h+xk)G/s = r(h+xk)G / (h+kx) = rG ### Go语言中椭圆曲线的实现 椭圆曲线的接口定义: ```go type Curve interface { //获取椭圆曲线参数 Params() *CurveParams //是否在曲线上 IsOnCurve(x, y *big.Int) bool //加法 Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int) //二倍运算 Double(x1, y1 *big.Int) (x, y *big.Int) //k*(Bx,By) ScalarMult(x1, y1 *big.Int, k []byte) (x, y *big.Int) //k*G, G为基点 ScalarBaseMult(k []byte) (x, y *big.Int) } //代码位置src/crypto/elliptic/elliptic.go ``` 椭圆曲线的接口实现: ```go type CurveParams struct { //有限域GF(p)中质数p P *big.Int //G点的阶 //如果存在最小正整数n,使得nG=O∞,则n为G点的阶 N *big.Int //椭圆曲线方程y²= x³-3x+b中常数b B *big.Int //G点(x,y) Gx, Gy *big.Int //密钥长度 BitSize int //椭圆曲线名称 Name string } func (curve *CurveParams) Params() *CurveParams { //获取椭圆曲线参数,即curve,代码略 } func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool { //是否在曲线y²=x³-3x+b上,代码略 } func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) { //加法运算,代码略 } func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) { //二倍运算,代码略 } func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) { //k*(Bx,By),代码略 } func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) { //k*G, G为基点,代码略 } //代码位置src/crypto/elliptic/elliptic.go ``` ### Go语言中椭圆曲线签名的实现 Go标准库中实现的椭圆曲线签名原理,与上述理论中基本接近。 相关证明方法已注释在代码中。 ```go //公钥 type PublicKey struct { elliptic.Curve X, Y *big.Int } //私钥 type PrivateKey struct { PublicKey //嵌入公钥 D *big.Int //私钥 } func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) { entropylen := (priv.Curve.Params().BitSize + 7) / 16 if entropylen > 32 { entropylen = 32 } entropy := make([]byte, entropylen) _, err = io.ReadFull(rand, entropy) if err != nil { return } md := sha512.New() md.Write(priv.D.Bytes()) //私钥 md.Write(entropy) md.Write(hash) key := md.Sum(nil)[:32] block, err := aes.NewCipher(key) if err != nil { return nil, nil, err } csprng := cipher.StreamReader{ R: zeroReader, S: cipher.NewCTR(block, []byte(aesIV)), } c := priv.PublicKey.Curve //椭圆曲线 N := c.Params().N //G点的阶 if N.Sign() == 0 { return nil, nil, errZeroParam } var k, kInv *big.Int for { for { //取随机数k k, err = randFieldElement(c, csprng) if err != nil { r = nil return } //求k在有限域GF(P)的逆,即1/k if in, ok := priv.Curve.(invertible); ok { kInv = in.Inverse(k) } else { kInv = fermatInverse(k, N) // N != 0 } //求r = kG r, _ = priv.Curve.ScalarBaseMult(k.Bytes()) r.Mod(r, N) if r.Sign() != 0 { break } } e := hashToInt(hash, c) //e即哈希 s = new(big.Int).Mul(priv.D, r) //Dr,即DkG s.Add(s, e) //e+DkG s.Mul(s, kInv) //(e+DkG)/k s.Mod(s, N) // N != 0 if s.Sign() != 0 { break } //签名为{r, s},即{kG, (e+DkG)/k} } return } //验证签名 func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool { c := pub.Curve //椭圆曲线 N := c.Params().N //G点的阶 if r.Sign() <= 0 || s.Sign() <= 0 { return false } if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 { return false } e := hashToInt(hash, c) //e即哈希 var w *big.Int //求s在有限域GF(P)的逆,即1/s if in, ok := c.(invertible); ok { w = in.Inverse(s) } else { w = new(big.Int).ModInverse(s, N) } u1 := e.Mul(e, w) //即e/s u1.Mod(u1, N) u2 := w.Mul(r, w) //即r/s u2.Mod(u2, N) var x, y *big.Int if opt, ok := c.(combinedMult); ok { x, y = opt.CombinedMult(pub.X, pub.Y, u1.Bytes(), u2.Bytes()) } else { x1, y1 := c.ScalarBaseMult(u1.Bytes()) //即eG/s x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes()) //即DGr/s //即eG/s + DGr/s = (e + Dr)G/s //= (e + Dr)kG / (e + DkG) = (e + Dr)r / (e + Dr) = r x, y = c.Add(x1, y1, x2, y2) } if x.Sign() == 0 && y.Sign() == 0 { return false } x.Mod(x, N) return x.Cmp(r) == 0 } //代码位置src/crypto/ecdsa/ecdsa.go ``` ### 后记 椭圆曲线数字签名算法,因其高安全性,目前已广泛应用在比特币、以太坊、超级账本等区块链项目中。 感谢关注兄弟连区块链教程分享!
兄弟连区块链教程区块链信息安全3椭圆曲线加解密及签名算法   兄弟连区块链教程区块链信息安全3椭圆曲线加解密及签名算法的技术原理一,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。 # 椭圆曲线加解密及签名算法的技术原理及其Go语言实现 椭圆曲线加密算法,即:Elliptic Curve Cryptography,简称ECC,是基于椭圆曲线数学理论实现的一种非对称加密算法。 相比RSA,ECC优势是可以使用更短的密钥,来实现与RSA相当或更高的安全。 据研究,160位ECC加密安全性相当于1024位RSA加密,210位ECC加密安全性相当于2048位RSA加密。 椭圆曲线在密码学中的使用,是1985年由Neal Koblitz和Victor Miller分别独立提出的。 ### 椭圆曲线 一般,椭圆曲线可以用如下二元三阶方程表示: y² = x³ + ax + b,其中a、b为系数。 如果满足条件4a³+27b²≠0,则可以基于E(a, b)定义一个群。 ### 定义椭圆曲线的运算规则 椭圆曲线上的运算规则,由如下方式定义: 加法:过曲线上的两点A、B画一条直线,找到直线与椭圆曲线的交点,交点关于x轴对称位置的点,定义为A+B,即为加法。 二倍运算:上述方法无法解释A + A,即两点重合的情况。 因此在这种情况下,将椭圆曲线在A点的切线,与椭圆曲线的交点,交点关于x轴对称位置的点,定义为A + A,即2A,即为二倍运算。 A + A = 2A = B 正负取反:将A关于x轴对称位置的点定义为-A,即椭圆曲线的正负取反运算。 无穷远点:如果将A与-A相加,过A与-A的直线平行于y轴,可以认为直线与椭圆曲线相交于无穷远点。 综上,定义了A+B、2A运算,因此给定椭圆曲线的某一点G,可以求出2G、3G(即G + 2G)、4G......。 即:当给定G点时,已知x,求xG点并不困难。反之,已知xG点,求x则非常困难。 此即为椭圆曲线加密算法背后的数学原理。 ### 有限域上的椭圆曲线运算 椭圆曲线要形成一条光滑的曲线,要求x,y取值均为实数,即实数域上的椭圆曲线。 但椭圆曲线加密算法,并非使用实数域,而是使用有限域。 按数论定义,有限域GF(p)指给定某个质数p,由0、1、2......p-1共p个元素组成的整数集合中定义的加减乘除运算。 假设椭圆曲线为y² = x³ + x + 1,其在有限域GF(23)上时,写作: y² ≡ x³ + x + 1 (mod 23) 此时,椭圆曲线不再是一条光滑曲线,而是一些不连续的点。 以点(1,7)为例,7² ≡ 1³ + 1 + 1 ≡ 3 (mod 23)。如此还有如下点: (0,1) (0,22) (1,7) (1,16) (3,10) (3,13) (4,0) (5,4) (5,19) (6,4) (6,19) (7,11) (7,12) (9,7) (9,16) (11,3) (11,20) 等等。 另外,如果P(x,y)为椭圆曲线上的点,则-P即(x,-y)也为椭圆曲线上的点。 如点P(0,1),-P=(0,-1)=(0,22)也为椭圆曲线上的点。 ### 计算xG 相关公式如下: 有限域GF(p)上的椭圆曲线y² = x³ + ax + b,若P(Xp, Yp), Q(Xq, Yq),且P≠-Q,则R(Xr,Yr) = P+Q 由如下规则确定: * Xr = (λ² - Xp - Xq) mod p * Yr = (λ(Xp - Xr) - Yp) mod p * 其中λ = (Yq - Yp)/(Xq - Xp) mod p(若P≠Q), λ = (3Xp² + a)/2Yp mod p(若P=Q) 因此,有限域GF(23)上的椭圆曲线y² ≡ x³ + x + 1 (mod 23),假设以(0,1)为G点,计算2G、3G、4G...xG等等,方法如下: 计算2G: * λ = (3x0² + 1)/2x1 mod 23 = (1/2) mod 23 = 12 * Xr = (12² - 0 - 0) mod 23 = 6 * Yr = (12(0 - 6) - 1) mod 23 = 19 即2G为点(6,19) 计算3G: 3G = G + 2G,即(0,1) + (6,19) * λ = (19 - 1)/(6 - 0) mod 23 = 3 * Xr = (3² - 0 - 6) mod 23 = 3 * Yr = (3(0 - 3) - 1) mod 23 = 13 即3G为点(3, 13) 同理计算4G、5G...xG 未完待续感谢关注兄弟连区块链教程分享!
兄弟连区块链教程Fabric1.0源代码分析Tx(Transaction 交易)一   兄弟连区块链教程Fabric1.0源代码分析Tx(Transaction 交易)一,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。 # Fabric 1.0源代码笔记 之 Tx(Transaction 交易) ## 1、Tx概述 Tx,即Transaction,交易或事务。 Tx代码分布目录结构如下: * protos/common/common.pb.go,交易的封装即Envelope结构体。也包括Payload、Header、ChannelHeader和SignatureHeader。 * protos/utils目录,交易相关部分工具函数,包括txutils.go、proputils.go和commonutils.go。 * core/ledger/kvledger/txmgmt目录 * rwsetutil目录,读写集相关结构体及方法。 * version目录,version.Height结构体及方法。 * validator目录,Validator接口及实现。 * txmgr目录,TxMgr接口及实现。 ## 2、交易的封装Envelope结构体 有个图4 ### 2.1、Envelope结构体 Envelope直译为信封,封装Payload和Signature。 ```go type Envelope struct { //用签名包装Payload,以便对信息做身份验证 Payload []byte //Payload序列化 Signature []byte //Payload header中指定的创建者签名 } //代码在protos/common/common.pb.go ``` ### 2.2、Payload相关结构体 Payload直译为有效载荷。Payload结构体: ```go type Payload struct { Header *Header //Header Data []byte //Transaction序列化 } //代码在protos/common/common.pb.go ``` Header结构体: ```go type Header struct { ChannelHeader []byte SignatureHeader []byte } //代码在protos/common/common.pb.go ``` ChannelHeader结构体: ```go type ChannelHeader struct { Type int32 Version int32 //消息协议版本 Timestamp *google_protobuf.Timestamp //创建消息时的本地时间 ChannelId string //消息绑定的ChannelId TxId string //TxId Epoch uint64 //纪元 Extension []byte //可附加的扩展 } //代码在protos/common/common.pb.go ``` 补充HeaderType: ```go type HeaderType int32 const ( HeaderType_MESSAGE HeaderType = 0 HeaderType_CONFIG HeaderType = 1 HeaderType_CONFIG_UPDATE HeaderType = 2 HeaderType_ENDORSER_TRANSACTION HeaderType = 3 HeaderType_ORDERER_TRANSACTION HeaderType = 4 HeaderType_DELIVER_SEEK_INFO HeaderType = 5 HeaderType_CHAINCODE_PACKAGE HeaderType = 6 ) //代码在protos/common/common.pb.go ``` SignatureHeader结构体: ```go type SignatureHeader struct { Creator []byte //消息的创建者, 指定为证书链 Nonce []byte //可能只使用一次的任意数字,可用于检测重播攻击 } //代码在protos/common/common.pb.go ``` ### 2.3、Transaction相关结构体 Transaction结构体: ```go type Transaction struct { Actions []*TransactionAction //Payload.Data是个TransactionAction数组,容纳每个交易 } //代码在protos/peer/transaction.pb.go ``` TransactionAction结构体: ```go type TransactionAction struct { Header []byte Payload []byte } //代码在protos/peer/transaction.pb.go ``` ### 2.4、ChaincodeActionPayload相关结构体 ChaincodeActionPayload结构体: ```go type ChaincodeActionPayload struct { ChaincodeProposalPayload []byte Action *ChaincodeEndorsedAction } //代码在protos/peer/transaction.pb.go ``` ChaincodeEndorsedAction结构体: ```go type ChaincodeEndorsedAction struct { ProposalResponsePayload []byte //ProposalResponsePayload序列化 Endorsements []*Endorsement } //代码在protos/peer/transaction.pb.go ``` ProposalResponsePayload结构体: ```go type ProposalResponsePayload struct { ProposalHash []byte Extension []byte //ChaincodeAction序列化 } //代码在protos/peer/proposal_response.pb.go ``` ChaincodeAction结构体: ```go type ChaincodeAction struct { Results []byte //TxRwSet序列化 Events []byte Response *Response ChaincodeId *ChaincodeID } //代码在protos/peer/proposal.pb.go ``` ## 3、交易验证代码TxValidationFlags TxValidationFlags是交易验证代码的数组,在commiter验证块时使用。 ```go type TxValidationFlags []uint8 //创建TxValidationFlags数组 func NewTxValidationFlags(size int) TxValidationFlags //为指定的交易设置交易验证代码 func (obj TxValidationFlags) SetFlag(txIndex int, flag peer.TxValidationCode) //获取指定交易的交易验证代码 func (obj TxValidationFlags) Flag(txIndex int) peer.TxValidationCode //检查指定的交易是否有效 func (obj TxValidationFlags) IsValid(txIndex int) bool //检查指定的交易是否无效 func (obj TxValidationFlags) IsInvalid(txIndex int) bool //指定交易的交易验证代码与flag比较,相同为true func (obj TxValidationFlags) IsSetTo(txIndex int, flag peer.TxValidationCode) bool //代码在core/ledger/util/txvalidationflags.go ``` 补充peer.TxValidationCode: ```go type TxValidationCode int32 const ( TxValidationCode_VALID TxValidationCode = 0 TxValidationCode_NIL_ENVELOPE TxValidationCode = 1 TxValidationCode_BAD_PAYLOAD TxValidationCode = 2 TxValidationCode_BAD_COMMON_HEADER TxValidationCode = 3 TxValidationCode_BAD_CREATOR_SIGNATURE TxValidationCode = 4 TxValidationCode_INVALID_ENDORSER_TRANSACTION TxValidationCode = 5 TxValidationCode_INVALID_CONFIG_TRANSACTION TxValidationCode = 6 TxValidationCode_UNSUPPORTED_TX_PAYLOAD TxValidationCode = 7 TxValidationCode_BAD_PROPOSAL_TXID TxValidationCode = 8 TxValidationCode_DUPLICATE_TXID TxValidationCode = 9 TxValidationCode_ENDORSEMENT_POLICY_FAILURE TxValidationCode = 10 TxValidationCode_MVCC_READ_CONFLICT TxValidationCode = 11 TxValidationCode_PHANTOM_READ_CONFLICT TxValidationCode = 12 TxValidationCode_UNKNOWN_TX_TYPE TxValidationCode = 13 TxValidationCode_TARGET_CHAIN_NOT_FOUND TxValidationCode = 14 TxValidationCode_MARSHAL_TX_ERROR TxValidationCode = 15 TxValidationCode_NIL_TXACTION TxValidationCode = 16 TxValidationCode_EXPIRED_CHAINCODE TxValidationCode = 17 TxValidationCode_CHAINCODE_VERSION_CONFLICT TxValidationCode = 18 TxValidationCode_BAD_HEADER_EXTENSION TxValidationCode = 19 TxValidationCode_BAD_CHANNEL_HEADER TxValidationCode = 20 TxValidationCode_BAD_RESPONSE_PAYLOAD TxValidationCode = 21 TxValidationCode_BAD_RWSET TxValidationCode = 22 TxValidationCode_ILLEGAL_WRITESET TxValidationCode = 23 TxValidationCode_INVALID_OTHER_REASON TxValidationCode = 255 ) //代码在protos/peer/transaction.pb.go ``` 未完待续感谢关注兄弟连区块链教程分享!
兄弟连区块链教程Fabric1.0源代码分析(protos/utils工具包)   兄弟连区块链教程Fabric1.0源代码分析putils(protos/utils工具包),2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。 # Fabric1.0源代码笔记之putils(protos/utils工具包) ## 1、putils概述 putils,即protos/utils工具包,代码分布在:protos/utils目录下。 包括:txutils.go、proputils.go、commonutils.go、blockutils.go。 ## 2、txutils ```go //TransactionAction.Payload => ChaincodeActionPayload //ChaincodeActionPayload.Action.ProposalResponsePayload => ProposalResponsePayload //ProposalResponsePayload.Extension => ChaincodeAction //从TransactionAction中获取ChaincodeActionPayload和ChaincodeAction func GetPayloads(txActions *peer.TransactionAction) (*peer.ChaincodeActionPayload, *peer.ChaincodeAction, error) //[]byte反序列化为Envelope func GetEnvelopeFromBlock(data []byte) (*common.Envelope, error) func CreateSignedEnvelope(txType common.HeaderType, channelID string, signer crypto.LocalSigner, dataMsg proto.Message, msgVersion int32, epoch uint64) (*common.Envelope, error) //由Proposal创建签名交易Envelope func CreateSignedTx(proposal *peer.Proposal, signer msp.SigningIdentity, resps ...*peer.ProposalResponse) (*common.Envelope, error) { func CreateProposalResponse(hdrbytes []byte, payl []byte, response *peer.Response, results []byte, events []byte, ccid *peer.ChaincodeID, visibility []byte, signingEndorser msp.SigningIdentity) (*peer.ProposalResponse, error) func CreateProposalResponseFailure(hdrbytes []byte, payl []byte, response *peer.Response, results []byte, events []byte, ccid *peer.ChaincodeID, visibility []byte) (*peer.ProposalResponse, error) //签名Proposal func GetSignedProposal(prop *peer.Proposal, signer msp.SigningIdentity) (*peer.SignedProposal, error) func GetSignedEvent(evt *peer.Event, signer msp.SigningIdentity) (*peer.SignedEvent, error) func MockSignedEndorserProposalOrPanic(chainID string, cs *peer.ChaincodeSpec, creator, signature []byte) (*peer.SignedProposal, *peer.Proposal) func MockSignedEndorserProposal2OrPanic(chainID string, cs *peer.ChaincodeSpec, signer msp.SigningIdentity) (*peer.SignedProposal, *peer.Proposal) func GetBytesProposalPayloadForTx(payload *peer.ChaincodeProposalPayload, visibility []byte) ([]byte, error) func GetProposalHash2(header *common.Header, ccPropPayl []byte) ([]byte, error) func GetProposalHash1(header *common.Header, ccPropPayl []byte, visibility []byte) ([]byte, error) //代码在protos/utils/txutils.go ``` ## 3、proputils ```go func GetChaincodeInvocationSpec(prop *peer.Proposal) (*peer.ChaincodeInvocationSpec, error) func GetChaincodeProposalContext(prop *peer.Proposal) ([]byte, map[string][]byte, error) //反序列化为common.Header func GetHeader(bytes []byte) (*common.Header, error) func GetNonce(prop *peer.Proposal) ([]byte, error) //Header.ChannelHeader反序列化为peer.ChaincodeHeaderExtension func GetChaincodeHeaderExtension(hdr *common.Header) (*peer.ChaincodeHeaderExtension, error) func GetProposalResponse(prBytes []byte) (*peer.ProposalResponse, error) func GetChaincodeDeploymentSpec(code []byte) (*peer.ChaincodeDeploymentSpec, error) func GetChaincodeAction(caBytes []byte) (*peer.ChaincodeAction, error) func GetResponse(resBytes []byte) (*peer.Response, error) func GetChaincodeEvents(eBytes []byte) (*peer.ChaincodeEvent, error) func GetProposalResponsePayload(prpBytes []byte) (*peer.ProposalResponsePayload, error) func GetProposal(propBytes []byte) (*peer.Proposal, error) //e.Payload反序列化为Payload func GetPayload(e *common.Envelope) (*common.Payload, error) //[]byte反序列化为Transaction func GetTransaction(txBytes []byte) (*peer.Transaction, error) func GetChaincodeActionPayload(capBytes []byte) (*peer.ChaincodeActionPayload, error) //反序列化为peer.ChaincodeProposalPayload func GetChaincodeProposalPayload(bytes []byte) (*peer.ChaincodeProposalPayload, error) //反序列化为common.SignatureHeader func GetSignatureHeader(bytes []byte) (*common.SignatureHeader, error) func CreateChaincodeProposal(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) func CreateChaincodeProposalWithTransient(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) func CreateChaincodeProposalWithTxIDNonceAndTransient(txid string, typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, nonce, creator []byte, transientMap map[string][]byte) (*peer.Proposal, string, error) func GetBytesProposalResponsePayload(hash []byte, response *peer.Response, result []byte, event []byte, ccid *peer.ChaincodeID) ([]byte, error) func GetBytesChaincodeProposalPayload(cpp *peer.ChaincodeProposalPayload) ([]byte, error) func GetBytesResponse(res *peer.Response) ([]byte, error) func GetBytesChaincodeEvent(event *peer.ChaincodeEvent) ([]byte, error) func GetBytesChaincodeActionPayload(cap *peer.ChaincodeActionPayload) ([]byte, error) func GetBytesProposalResponse(pr *peer.ProposalResponse) ([]byte, error) func GetBytesProposal(prop *peer.Proposal) ([]byte, error) func GetBytesHeader(hdr *common.Header) ([]byte, error) func GetBytesSignatureHeader(hdr *common.SignatureHeader) ([]byte, error) func GetBytesTransaction(tx *peer.Transaction) ([]byte, error) func GetBytesPayload(payl *common.Payload) ([]byte, error) func GetBytesEnvelope(env *common.Envelope) ([]byte, error) //从envBytes []byte中获取ChaincodeAction func GetActionFromEnvelope(envBytes []byte) (*peer.ChaincodeAction, error) func CreateProposalFromCIS(typ common.HeaderType, chainID string, cis *peer.ChaincodeInvocationSpec, creator []byte) (*peer.Proposal, string, error) func CreateInstallProposalFromCDS(ccpack proto.Message, creator []byte) (*peer.Proposal, string, error) //按ChaincodeDeploymentSpec创建DeployProposal func CreateDeployProposalFromCDS(chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, string, error) func CreateUpgradeProposalFromCDS(chainID string, cds *peer.ChaincodeDeploymentSpec, creator []byte, policy []byte, escc []byte, vscc []byte) (*peer.Proposal, string, error) func createProposalFromCDS(chainID string, msg proto.Message, creator []byte, policy []byte, escc []byte, vscc []byte, propType string) (*peer.Proposal, string, error) func ComputeProposalTxID(nonce, creator []byte) (string, error) func CheckProposalTxID(txid string, nonce, creator []byte) error func ComputeProposalBinding(proposal *peer.Proposal) ([]byte, error) func computeProposalBindingInternal(nonce, creator []byte, epoch uint64) ([]byte, error) //代码在protos/utils/proputils.go ``` ## 4、commonutils ```go func MarshalOrPanic(pb proto.Message) []byte func Marshal(pb proto.Message) ([]byte, error) func CreateNonceOrPanic() []byte func CreateNonce() ([]byte, error) func UnmarshalPayloadOrPanic(encoded []byte) *cb.Payload func UnmarshalPayload(encoded []byte) (*cb.Payload, error) func UnmarshalEnvelopeOrPanic(encoded []byte) *cb.Envelope func UnmarshalEnvelope(encoded []byte) (*cb.Envelope, error) func UnmarshalEnvelopeOfType(envelope *cb.Envelope, headerType cb.HeaderType, message proto.Message) (*cb.ChannelHeader, error) func ExtractEnvelopeOrPanic(block *cb.Block, index int) *cb.Envelope func ExtractEnvelope(block *cb.Block, index int) (*cb.Envelope, error) func ExtractPayloadOrPanic(envelope *cb.Envelope) *cb.Payload func ExtractPayload(envelope *cb.Envelope) (*cb.Payload, error) func MakeChannelHeader(headerType cb.HeaderType, version int32, chainID string, epoch uint64) *cb.ChannelHeader func MakeSignatureHeader(serializedCreatorCertChain []byte, nonce []byte) *cb.SignatureHeader func SetTxID(channelHeader *cb.ChannelHeader, signatureHeader *cb.SignatureHeader) error func MakePayloadHeader(ch *cb.ChannelHeader, sh *cb.SignatureHeader) *cb.Header func NewSignatureHeaderOrPanic(signer crypto.LocalSigner) *cb.SignatureHeader func SignOrPanic(signer crypto.LocalSigner, msg []byte) []byte //[]byte反序列化为ChannelHeader func UnmarshalChannelHeader(bytes []byte) (*cb.ChannelHeader, error) func UnmarshalChaincodeID(bytes []byte) (*pb.ChaincodeID, error) func IsConfigBlock(block *cb.Block) bool //代码在protos/utils/commonutils.go ``` ## 5、blockutils ```go //[]byte转换为Block,从Block中获取ChainID(即ChannelId) func GetChainIDFromBlockBytes(bytes []byte) (string, error) //从Block中获取ChainID(即ChannelId) func GetChainIDFromBlock(block *cb.Block) (string, error) //从Block中按index获取Metadata func GetMetadataFromBlock(block *cb.Block, index cb.BlockMetadataIndex) (*cb.Metadata, error) //从Block中按index获取Metadata,如果失败则Panic func GetMetadataFromBlockOrPanic(block *cb.Block, index cb.BlockMetadataIndex) *cb.Metadata //从Block.Metadata.Metadata中获取LastConfig func GetLastConfigIndexFromBlock(block *cb.Block) (uint64, error) //从Block.Metadata.Metadata中获取LastConfig,如果失败则Panic func GetLastConfigIndexFromBlockOrPanic(block *cb.Block) uint64 //[]byte转换为Block func GetBlockFromBlockBytes(blockBytes []byte) (*cb.Block, error) //拷贝Block.Metadata func CopyBlockMetadata(src *cb.Block, dst *cb.Block) //初始化Block.Metadata.Metadata func InitBlockMetadata(block *cb.Block) //代码在protos/utils/blockutils.go ``` 感谢关注兄弟连区块链教程分享!
兄弟连区块链教程Fabric1.0源代码分析Proposal(提案)   **区块链教程**Fabric1.0源代码分析Proposal(提案),2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。 # Fabric1.0源代码笔记之Proposal(提案) ## 1、Proposal概述 Proposal,即向Endorser发起的提案。 Proposal代码分布在protos/utils、protos/peer目录下,目录结构如下: protos/utils目录: proputils.go,Proposal工具函数。 txutils.go,Proposal工具函数。 protos/peer目录: proposal.pb.go,Proposal相关结构体定义。 ## 2、Proposal相关结构体定义 2.1、SignedProposal定义 ```go type SignedProposal struct { ProposalBytes []byte //Proposal序列化,即type Proposal struct Signature []byte //signer.Sign(ProposalBytes) } //代码在protos/peer/proposal.pb.go ``` ### 2.2、Proposal定义 ```go type Proposal struct { Header []byte //Header序列化,即type Header struct Payload []byte //ChaincodeProposalPayload序列化,即type ChaincodeProposalPayload struct Extension []byte //扩展 } //代码在protos/peer/proposal.pb.go ``` ### 2.3、ChaincodeProposalPayload定义 ```go type ChaincodeProposalPayload struct { Input []byte //ChaincodeInvocationSpec序列化,即type ChaincodeInvocationSpec struct TransientMap map[string][]byte //瞬态映射 } //代码在protos/peer/proposal.pb.go ``` ## 3、ProposalResponse结构体定义 ### 3.1、ProposalResponse定义 ```go type ProposalResponse struct { Version int32 Timestamp *google_protobuf1.Timestamp Response *Response //type Response struct,peer.Response{Status: 200, Message: "OK"}} Payload []byte Endorsement *Endorsement //type Endorsement struct } //代码在protos/peer/proposal_response.pb.go ``` ### 3.2、Response定义 ```go type Response struct { //peer.Response{Status: 200, Message: "OK"}} Status int32 Message string Payload []byte } //代码在protos/peer/proposal_response.pb.go ``` ### 3.3、Endorsement定义 ```go type Endorsement struct { Endorser []byte //bccspmsp.signer Signature []byte } //代码在protos/peer/proposal_response.pb.go ```
兄弟连区块链教程Fabric1.0源代码分析policy(背书策略)   兄弟连区块链教程Fabric1.0源代码分析policy(背书策略),2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。 # Fabric 1.0源代码笔记 之 policy(背书策略) ## 1、policy概述 policy代码分布在core/policy、core/policyprovider、common/policies目录下。目录结构如下: * core/policy/policy.go,PolicyChecker接口定义及实现、PolicyCheckerFactory接口定义。 * core/policyprovider/provider.go,PolicyChecker工厂默认实现。 * common/policies目录 * policy.go,ChannelPolicyManagerGetter接口及实现。 * implicitmeta_util.go,通道策略工具函数。 ## 2、PolicyChecker工厂 ### 2.1、PolicyCheckerFactory接口定义 ```go type PolicyCheckerFactory interface { NewPolicyChecker() PolicyChecker //构造PolicyChecker实例 } var pcFactory PolicyCheckerFactory //全局变量定义及赋值函数 func RegisterPolicyCheckerFactory(f PolicyCheckerFactory) { pcFactory = f } //代码在core/policy/policy.go ``` ### 2.2、PolicyCheckerFactory接口默认实现 ```go type defaultFactory struct{} //构造policy.PolicyChecker func (f *defaultFactory) NewPolicyChecker() policy.PolicyChecker { return policy.NewPolicyChecker( peer.NewChannelPolicyManagerGetter(), //&channelPolicyManagerGetter{} mgmt.GetLocalMSP(), mgmt.NewLocalMSPPrincipalGetter(), ) } //获取policy.PolicyChecker,即调用policy.GetPolicyChecker() func GetPolicyChecker() policy.PolicyChecker func init() { //初始化全局变量pcFactory policy.RegisterPolicyCheckerFactory(&defaultFactory{}) } ``` ## 3、PolicyChecker接口定义及实现 ### 3.1、PolicyChecker接口定义 ```go type PolicyChecker interface { CheckPolicy(channelID, policyName string, signedProp *pb.SignedProposal) error CheckPolicyBySignedData(channelID, policyName string, sd []*common.SignedData) error CheckPolicyNoChannel(policyName string, signedProp *pb.SignedProposal) error } //代码在core/policy/policy.go ``` ### 3.2、PolicyChecker接口实现 PolicyChecker接口实现,即policyChecker结构体及方法。 ```go type policyChecker struct { channelPolicyManagerGetter policies.ChannelPolicyManagerGetter //通道策略管理器 localMSP msp.IdentityDeserializer //身份 principalGetter mgmt.MSPPrincipalGetter //委托人 } //构造policyChecker func NewPolicyChecker(channelPolicyManagerGetter policies.ChannelPolicyManagerGetter, localMSP msp.IdentityDeserializer, principalGetter mgmt.MSPPrincipalGetter) PolicyChecker //检查签名提案是否符合通道策略 func (p *policyChecker) CheckPolicy(channelID, policyName string, signedProp *pb.SignedProposal) error func (p *policyChecker) CheckPolicyNoChannel(policyName string, signedProp *pb.SignedProposal) error //检查签名数据是否符合通道策略,获取策略并调取policy.Evaluate(sd) func (p *policyChecker) CheckPolicyBySignedData(channelID, policyName string, sd []*common.SignedData) error func GetPolicyChecker() PolicyChecker //pcFactory.NewPolicyChecker() //代码在core/policy/policy.go ``` func (p *policyChecker) CheckPolicy(channelID, policyName string, signedProp *pb.SignedProposal) error代码如下: ```go func (p *policyChecker) CheckPolicy(channelID, policyName string, signedProp *pb.SignedProposal) error { if channelID == "" { //channelID为空,调取CheckPolicyNoChannel() return p.CheckPolicyNoChannel(policyName, signedProp) } policyManager, _ := p.channelPolicyManagerGetter.Manager(channelID) proposal, err := utils.GetProposal(signedProp.ProposalBytes) //获取proposal header, err := utils.GetHeader(proposal.Header) shdr, err := utils.GetSignatureHeader(header.SignatureHeader) //SignatureHeader sd := []*common.SignedData{&common.SignedData{ Data: signedProp.ProposalBytes, Identity: shdr.Creator, Signature: signedProp.Signature, }} return p.CheckPolicyBySignedData(channelID, policyName, sd) } //代码在core/policy/policy.go ``` ## 4、ChannelPolicyManagerGetter接口及实现 ### 4.1、ChannelPolicyManagerGetter接口定义 ```go type ChannelPolicyManagerGetter interface { Manager(channelID string) (Manager, bool) } //代码在common/policies/policy.go ``` ### 4.2、ChannelPolicyManagerGetter接口实现 ChannelPolicyManagerGetter接口实现,即ManagerImpl结构体及方法。 ```go type ManagerImpl struct { parent *ManagerImpl basePath string fqPrefix string providers map[int32]Provider //type Provider interface config *policyConfig //type policyConfig struct pendingConfig map[interface{}]*policyConfig //type policyConfig struct pendingLock sync.RWMutex SuppressSanityLogMessages bool } type Provider interface { NewPolicy(data []byte) (Policy, proto.Message, error) } type policyConfig struct { policies map[string]Policy //type Policy interface managers map[string]*ManagerImpl imps []*implicitMetaPolicy } type Policy interface { //对给定的签名数据,按规则检验确认是否符合约定的条件 Evaluate(signatureSet []*cb.SignedData) error } //构造ManagerImpl func NewManagerImpl(basePath string, providers map[int32]Provider) *ManagerImpl //获取pm.basePath func (pm *ManagerImpl) BasePath() string //获取pm.config.policies,即map[string]Policy中Key列表 func (pm *ManagerImpl) PolicyNames() []string //获取指定路径的子管理器 func (pm *ManagerImpl) Manager(path []string) (Manager, bool) //获取pm.config.policies[relpath] //获取Policy func (pm *ManagerImpl) GetPolicy(id string) (Policy, bool) func (pm *ManagerImpl) BeginPolicyProposals(tx interface{}, groups []string) ([]Proposer, error) func (pm *ManagerImpl) RollbackProposals(tx interface{}) func (pm *ManagerImpl) PreCommit(tx interface{}) error func (pm *ManagerImpl) CommitProposals(tx interface{}) func (pm *ManagerImpl) ProposePolicy(tx interface{}, key string, configPolicy *cb.ConfigPolicy) (proto.Message, error) //代码在common/policies/policy.go ``` ```go type implicitMetaPolicy struct { conf *cb.ImplicitMetaPolicy threshold int subPolicies []Policy } //代码在common/policies/implicitmeta.go ``` ## 5、通道策略工具函数 ```go type ImplicitMetaPolicy_Rule int32 const ( ImplicitMetaPolicy_ANY ImplicitMetaPolicy_Rule = 0 //任意 ImplicitMetaPolicy_ALL ImplicitMetaPolicy_Rule = 1 //所有 ImplicitMetaPolicy_MAJORITY ImplicitMetaPolicy_Rule = 2 //大多数 ) //代码在protos/common/policies.pb.go ``` ```go //构造cb.Policy func ImplicitMetaPolicyWithSubPolicy(subPolicyName string, rule cb.ImplicitMetaPolicy_Rule) *cb.ConfigPolicy func TemplateImplicitMetaPolicyWithSubPolicy(path []string, policyName string, subPolicyName string, rule cb.ImplicitMetaPolicy_Rule) *cb.ConfigGroup //调取TemplateImplicitMetaPolicyWithSubPolicy(path, policyName, policyName, rule) func TemplateImplicitMetaPolicy(path []string, policyName string, rule cb.ImplicitMetaPolicy_Rule) *cb.ConfigGroup //任意,TemplateImplicitMetaPolicy(path, policyName, cb.ImplicitMetaPolicy_ANY) func TemplateImplicitMetaAnyPolicy(path []string, policyName string) *cb.ConfigGroup //所有,TemplateImplicitMetaPolicy(path, policyName, cb.ImplicitMetaPolicy_ALL) func TemplateImplicitMetaAllPolicy(path []string, policyName string) *cb.ConfigGroup //大多数,TemplateImplicitMetaPolicy(path, policyName, cb.ImplicitMetaPolicy_MAJORITY) func TemplateImplicitMetaMajorityPolicy(path []string, policyName string) *cb.ConfigGroup //代码在common/policies/implicitmeta_util.go ```
兄弟连区块链教程Fabric1.0源代码分析Peer Deliver客户端   区块链教程Fabric1.0源代码分析Peer DeliverClient(Deliver客户端),2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。 # Fabric1.0源代码笔记之Peer DeliverClient(Deliver客户端) ## 1、DeliverClient概述 DeliverClient代码分布如下: * peer/channel/deliverclient.go,deliverClientIntf接口定义及实现,以及DeliverClient工具函数。 * protos/orderer/ab.pb.go,AtomicBroadcast_DeliverClient接口定义和实现。 ## 2、deliverClientIntf接口定义及实现 ### 2.1、DeliverClient工具函数 ```go //构造deliverClient func newDeliverClient(conn *grpc.ClientConn, client ab.AtomicBroadcast_DeliverClient, chainID string) *deliverClient //代码在peer/channel/deliverclient.go ``` ### 2.2、deliverClientIntf接口定义及实现 ```go type deliverClientIntf interface { getSpecifiedBlock(num uint64) (*common.Block, error) getOldestBlock() (*common.Block, error) getNewestBlock() (*common.Block, error) Close() error } type deliverClient struct { conn *grpc.ClientConn client ab.AtomicBroadcast_DeliverClient chainID string } //构造查询Envelope func seekHelper(chainID string, position *ab.SeekPosition) *common.Envelope //r.client.Send(seekHelper(r.chainID, &ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: blockNumber}}})) func (r *deliverClient) seekSpecified(blockNumber uint64) error //r.client.Send(seekHelper(r.chainID, &ab.SeekPosition{Type: &ab.SeekPosition_Oldest{Oldest: &ab.SeekOldest{}}})) func (r *deliverClient) seekOldest() error //return r.client.Send(seekHelper(r.chainID, &ab.SeekPosition{Type: &ab.SeekPosition_Newest{Newest: &ab.SeekNewest{}}})) func (r *deliverClient) seekNewest() error //r.client.Recv()读取块 func (r *deliverClient) readBlock() (*common.Block, error) //r.seekSpecified(num)和r.readBlock() func (r *deliverClient) getSpecifiedBlock(num uint64) (*common.Block, error) //r.seekOldest()和r.readBlock() func (r *deliverClient) getOldestBlock() (*common.Block, error) //r.seekNewest()和r.readBlock() func (r *deliverClient) getNewestBlock() (*common.Block, error) //r.conn.Close() func (r *deliverClient) Close() error //cf.DeliverClient.getSpecifiedBlock(0)获取创世区块 func getGenesisBlock(cf *ChannelCmdFactory) (*common.Block, error) //代码在peer/channel/deliverclient.go ``` func seekHelper(chainID string, position *ab.SeekPosition) *common.Envelope代码如下: ```go func seekHelper(chainID string, position *ab.SeekPosition) *common.Envelope { seekInfo := &ab.SeekInfo{ Start: position, Stop: position, Behavior: ab.SeekInfo_BLOCK_UNTIL_READY, } msgVersion := int32(0) epoch := uint64(0) env, err := utils.CreateSignedEnvelope(common.HeaderType_CONFIG_UPDATE, chainID, localmsp.NewSigner(), seekInfo, msgVersion, epoch) return env } //代码在peer/channel/deliverclient.go ``` 感谢关注兄弟连区块链教程分享!
兄弟连区块链教程Fabric1.0源代码分析Peer Broadcast客户端   兄弟连区块链教程Fabric1.0源代码分析PeerBroadcastClient(Broadcast客户端),2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。 # Fabric1.0源代码笔记之Peer DeliverClient(Deliver客户端) ## 1、DeliverClient概述 DeliverClient代码分布如下: * peer/channel/deliverclient.go,deliverClientIntf接口定义及实现,以及DeliverClient工具函数。 * protos/orderer/ab.pb.go,AtomicBroadcast_DeliverClient接口定义和实现。 ## 2、deliverClientIntf接口定义及实现 ### 2.1、DeliverClient工具函数 ```go //构造deliverClient func newDeliverClient(conn *grpc.ClientConn, client ab.AtomicBroadcast_DeliverClient, chainID string) *deliverClient //代码在peer/channel/deliverclient.go ``` ### 2.2、deliverClientIntf接口定义及实现 ```go type deliverClientIntf interface { getSpecifiedBlock(num uint64) (*common.Block, error) getOldestBlock() (*common.Block, error) getNewestBlock() (*common.Block, error) Close() error } type deliverClient struct { conn *grpc.ClientConn client ab.AtomicBroadcast_DeliverClient chainID string } //构造查询Envelope func seekHelper(chainID string, position *ab.SeekPosition) *common.Envelope //r.client.Send(seekHelper(r.chainID, &ab.SeekPosition{Type: &ab.SeekPosition_Specified{Specified: &ab.SeekSpecified{Number: blockNumber}}})) func (r *deliverClient) seekSpecified(blockNumber uint64) error //r.client.Send(seekHelper(r.chainID, &ab.SeekPosition{Type: &ab.SeekPosition_Oldest{Oldest: &ab.SeekOldest{}}})) func (r *deliverClient) seekOldest() error //return r.client.Send(seekHelper(r.chainID, &ab.SeekPosition{Type: &ab.SeekPosition_Newest{Newest: &ab.SeekNewest{}}})) func (r *deliverClient) seekNewest() error //r.client.Recv()读取块 func (r *deliverClient) readBlock() (*common.Block, error) //r.seekSpecified(num)和r.readBlock() func (r *deliverClient) getSpecifiedBlock(num uint64) (*common.Block, error) //r.seekOldest()和r.readBlock() func (r *deliverClient) getOldestBlock() (*common.Block, error) //r.seekNewest()和r.readBlock() func (r *deliverClient) getNewestBlock() (*common.Block, error) //r.conn.Close() func (r *deliverClient) Close() error //cf.DeliverClient.getSpecifiedBlock(0)获取创世区块 func getGenesisBlock(cf *ChannelCmdFactory) (*common.Block, error) //代码在peer/channel/deliverclient.go ``` func seekHelper(chainID string, position *ab.SeekPosition) *common.Envelope代码如下: ```go func seekHelper(chainID string, position *ab.SeekPosition) *common.Envelope { seekInfo := &ab.SeekInfo{ Start: position, Stop: position, Behavior: ab.SeekInfo_BLOCK_UNTIL_READY, } msgVersion := int32(0) epoch := uint64(0) env, err := utils.CreateSignedEnvelope(common.HeaderType_CONFIG_UPDATE, chainID, localmsp.NewSigner(), seekInfo, msgVersion, epoch) return env } //代码在peer/channel/deliverclient.go ``` 感谢关注兄弟连区块链教程分享!
区块链教程Fabric1.0源代码分析Orderer multichain   兄弟连区块链教程Fabric1.0源代码分析Orderer multichain,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。 # Fabric 1.0源代码笔记 之 Orderer #multichain(多链支持包) ## 1、multichain概述 multichain代码集中在orderer/multichain目录下,目录结构如下: * manager.go,Manager接口定义及实现。 * chainsupport.go,ChainSupport接口定义及实现。 * systemchain.go,system chain。 ## 2、Manager接口定义及实现 ### 2.1、Manager接口定义 用于链的创建和访问。 ```go type Manager interface { //获取ChainSupport,以及判断链是否存在 GetChain(chainID string) (ChainSupport, bool) //获取系统通道的通道ID SystemChannelID() string //支持通道创建请求 NewChannelConfig(envConfigUpdate *cb.Envelope) (configtxapi.Manager, error) } //代码在orderer/multichain/manager.go ``` ### 2.2、Manager接口实现 Manager接口实现,即multiLedger结构体及方法。 ```go type multiLedger struct { chains map[string]*chainSupport consenters map[string]Consenter ledgerFactory ledger.Factory signer crypto.LocalSigner systemChannelID string systemChannel *chainSupport } type configResources struct { configtxapi.Manager } type ledgerResources struct { *configResources ledger ledger.ReadWriter } //代码在orderer/multichain/manager.go ``` 涉及方法如下: ```go func (cr *configResources) SharedConfig() config.Orderer //获取配置交易Envelope func getConfigTx(reader ledger.Reader) *cb.Envelope //构造multiLedger func NewManagerImpl(ledgerFactory ledger.Factory, consenters map[string]Consenter, signer crypto.LocalSigner) Manager //获取系统链ID func (ml *multiLedger) SystemChannelID() string //按chainID获取ChainSupport func (ml *multiLedger) GetChain(chainID string) (ChainSupport, bool) //构造ledgerResources func (ml *multiLedger) newLedgerResources(configTx *cb.Envelope) *ledgerResources //创建新链 func (ml *multiLedger) newChain(configtx *cb.Envelope) //通道或链的个数 func (ml *multiLedger) channelsCount() int //支持创建新的通道 func (ml *multiLedger) NewChannelConfig(envConfigUpdate *cb.Envelope) (configtxapi.Manager, error) //代码在orderer/multichain/manager.go ``` func NewManagerImpl(ledgerFactory ledger.Factory, consenters map[string]Consenter, signer crypto.LocalSigner) Manager代码如下: ```go func NewManagerImpl(ledgerFactory ledger.Factory, consenters map[string]Consenter, signer crypto.LocalSigner) Manager { ml := &multiLedger{ chains: make(map[string]*chainSupport), ledgerFactory: ledgerFactory, consenters: consenters, signer: signer, } existingChains := ledgerFactory.ChainIDs() for _, chainID := range existingChains { rl, err := ledgerFactory.GetOrCreate(chainID) configTx := getConfigTx(rl) ledgerResources := ml.newLedgerResources(configTx) chainID := ledgerResources.ChainID() if _, ok := ledgerResources.ConsortiumsConfig(); ok { //系统链 chain := newChainSupport(createSystemChainFilters(ml, ledgerResources), ledgerResources, consenters, signer) ml.chains[chainID] = chain ml.systemChannelID = chainID ml.systemChannel = chain defer chain.start() } else { //普通链 chain := newChainSupport(createStandardFilters(ledgerResources), ledgerResources, consenters, signer) ml.chains[chainID] = chain chain.start() } } return ml } //代码在orderer/multichain/manager.go ``` ## 3、ChainSupport接口定义及实现 ### 3.1、ChainSupport接口定义 ```go type ChainSupport interface { PolicyManager() policies.Manager //策略管理 Reader() ledger.Reader Errored() <-chan struct{} broadcast.Support ConsenterSupport //嵌入ConsenterSupport接口 Sequence() uint64 //支持通道更新 ProposeConfigUpdate(env *cb.Envelope) (*cb.ConfigEnvelope, error) } type ConsenterSupport interface { crypto.LocalSigner BlockCutter() blockcutter.Receiver SharedConfig() config.Orderer CreateNextBlock(messages []*cb.Envelope) *cb.Block WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block ChainID() string Height() uint64 } type Consenter interface { //定义支持排序机制 HandleChain(support ConsenterSupport, metadata *cb.Metadata) (Chain, error) } type Chain interface { //接受消息 Enqueue(env *cb.Envelope) bool Errored() <-chan struct{} Start() //开始 Halt() //挂起 } //代码在orderer/multichain/chainsupport.go ``` ### 3.2、ChainSupport和ConsenterSupport接口实现 ChainSupport接口实现,即chainSupport结构体及方法。 ```go type chainSupport struct { *ledgerResources chain Chain cutter blockcutter.Receiver filters *filter.RuleSet signer crypto.LocalSigner lastConfig uint64 lastConfigSeq uint64 } //代码在orderer/multichain/chainsupport.go ``` 涉及方法如下: ```go //构造chainSupport func newChainSupport(filters *filter.RuleSet,ledgerResources *ledgerResources,consenters map[string]Consenter,signer crypto.LocalSigner,) *chainSupport func createStandardFilters(ledgerResources *ledgerResources) *filter.RuleSet func createSystemChainFilters(ml *multiLedger, ledgerResources *ledgerResources) *filter.RuleSet func (cs *chainSupport) start() func (cs *chainSupport) NewSignatureHeader() (*cb.SignatureHeader, error) func (cs *chainSupport) Sign(message []byte) ([]byte, error) func (cs *chainSupport) Filters() *filter.RuleSet func (cs *chainSupport) BlockCutter() blockcutter.Receiver func (cs *chainSupport) Reader() ledger.Reader func (cs *chainSupport) Enqueue(env *cb.Envelope) bool func (cs *chainSupport) Errored() <-chan struct{} //创建块,调取ledger.CreateNextBlock(cs.ledger, messages) func (cs *chainSupport) CreateNextBlock(messages []*cb.Envelope) *cb.Block func (cs *chainSupport) addBlockSignature(block *cb.Block) func (cs *chainSupport) addLastConfigSignature(block *cb.Block) //写入块 func (cs *chainSupport) WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block func (cs *chainSupport) Height() uint64 //代码在orderer/multichain/chainsupport.go ``` func (cs *chainSupport) WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block 代码如下: ```go func (cs *chainSupport) WriteBlock(block *cb.Block, committers []filter.Committer, encodedMetadataValue []byte) *cb.Block { for _, committer := range committers { committer.Commit() } cs.addBlockSignature(block) cs.addLastConfigSignature(block) err := cs.ledger.Append(block)//账本追加块 return block } //代码在orderer/multichain/chainsupport.go ```
兄弟连区块链教程Fabric1.0源代码分析Orderer BroadcastServer   **区块链教程**Fabric1.0源代码分析Orderer BroadcastServer,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。 # Fabric 1.0源代码笔记 之 Orderer #BroadcastServer(Broadcast服务端) ## 1、BroadcastServer概述 BroadcastServer相关代码在protos/orderer、orderer目录下。 protos/orderer/ab.pb.go,AtomicBroadcastServer接口定义。 orderer/server.go,go,AtomicBroadcastServer接口实现。 有个图 ## 2、AtomicBroadcastServer接口定义 ### 2.1、AtomicBroadcastServer接口定义 ```go type AtomicBroadcastServer interface { Broadcast(AtomicBroadcast_BroadcastServer) error Deliver(AtomicBroadcast_DeliverServer) error } //代码在protos/orderer/ab.pb.go ··· ### 2.2、gRPC相关实现 ```go var _AtomicBroadcast_serviceDesc = grpc.ServiceDesc{ ServiceName: "orderer.AtomicBroadcast", HandlerType: (*AtomicBroadcastServer)(nil), Methods: []grpc.MethodDesc{}, Streams: []grpc.StreamDesc{ { StreamName: "Broadcast", Handler: _AtomicBroadcast_Broadcast_Handler, ServerStreams: true, ClientStreams: true, }, { StreamName: "Deliver", Handler: _AtomicBroadcast_Deliver_Handler, ServerStreams: true, ClientStreams: true, }, }, Metadata: "orderer/ab.proto", } func RegisterAtomicBroadcastServer(s *grpc.Server, srv AtomicBroadcastServer) { s.RegisterService(&_AtomicBroadcast_serviceDesc, srv) } func _AtomicBroadcast_Broadcast_Handler(srv interface{}, stream grpc.ServerStream) error { return srv.(AtomicBroadcastServer).Broadcast(&atomicBroadcastBroadcastServer{stream}) } func _AtomicBroadcast_Deliver_Handler(srv interface{}, stream grpc.ServerStream) error { return srv.(AtomicBroadcastServer).Deliver(&atomicBroadcastDeliverServer{stream}) } //代码在protos/orderer/ab.pb.go ``` ## 3、AtomicBroadcastServer接口实现 ### 3.1、server结构体 server结构体: ```go type server struct { bh broadcast.Handler dh deliver.Handler } type broadcastSupport struct { multichain.Manager broadcast.ConfigUpdateProcessor } //代码在orderer/server.go ``` broadcast.Handler: ```go type Handler interface { Handle(srv ab.AtomicBroadcast_BroadcastServer) error } type handlerImpl struct { sm SupportManager } func NewHandlerImpl(sm SupportManager) Handler { return &handlerImpl{ sm: sm, } } type SupportManager interface { ConfigUpdateProcessor GetChain(chainID string) (Support, bool) } type ConfigUpdateProcessor interface { //处理通道配置更新 Process(envConfigUpdate *cb.Envelope) (*cb.Envelope, error) } //代码在orderer/common/broadcast/broadcast.go ``` deliver.Handler: ```go type Handler interface { Handle(srv ab.AtomicBroadcast_DeliverServer) error } type deliverServer struct { sm SupportManager } type SupportManager interface { GetChain(chainID string) (Support, bool) } //代码在orderer/common/deliver/deliver.go ``` ### 3.2、server结构体相关方法 ```go //构建server结构体 func NewServer(ml multichain.Manager, signer crypto.LocalSigner) ab.AtomicBroadcastServer //s.bh.Handle(srv) func (s *server) Broadcast(srv ab.AtomicBroadcast_BroadcastServer) error //s.dh.Handle(srv) func (s *server) Deliver(srv ab.AtomicBroadcast_DeliverServer) error //代码在orderer/server.go ``` func NewServer(ml multichain.Manager, signer crypto.LocalSigner) ab.AtomicBroadcastServer代码如下: ```go func NewServer(ml multichain.Manager, signer crypto.LocalSigner) ab.AtomicBroadcastServer { s := &server{ dh: deliver.NewHandlerImpl(deliverSupport{Manager: ml}), bh: broadcast.NewHandlerImpl(broadcastSupport{ Manager: ml, ConfigUpdateProcessor: configupdate.New(ml.SystemChannelID(), configUpdateSupport{Manager: ml}, signer), }), } return s } //代码在orderer/server.go ``` ### 3.3、Broadcast服务端Broadcast处理流程 Broadcast服务端Broadcast处理流程,即broadcast.handlerImpl.Handle方法。 #### 3.3.1、接收Envelope消息,并获取Payload和ChannelHeader ```go msg, err := srv.Recv() //接收Envelope消息 payload, err := utils.UnmarshalPayload(msg.Payload) //反序列化获取Payload chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) //反序列化获取ChannelHeader //代码在orderer/common/broadcast/broadcast.go ``` #### 3.3.2、如果消息类型为channel配置或更新,则使用multichain.Manager处理消息 ``` if chdr.Type == int32(cb.HeaderType_CONFIG_UPDATE) { //如果是channel配置或更新 msg, err = bh.sm.Process(msg) //configupdate.Processor.Process方法 } //代码在orderer/common/broadcast/broadcast.go ``` msg, err = bh.sm.Process(msg)代码如下: ```go func (p *Processor) Process(envConfigUpdate *cb.Envelope) (*cb.Envelope, error) { channelID, err := channelID(envConfigUpdate) //获取ChannelHeader.ChannelId //multichain.Manager.GetChain方法,获取chainSupport,以及chain是否存在 support, ok := p.manager.GetChain(channelID) if ok { //已存在的channel配置,调取multichain.Manager.ProposeConfigUpdate方法 return p.existingChannelConfig(envConfigUpdate, channelID, support) } //新channel配置,调取multichain.Manager.NewChannelConfig方法 return p.newChannelConfig(channelID, envConfigUpdate) } //代码在orderer/configupdate/configupdate.go ``` #### 3.3.3、其他消息类型或channel消息处理后,接受消息并加入排序 ```go support, ok := bh.sm.GetChain(chdr.ChannelId) //获取chainSupport _, filterErr := support.Filters().Apply(msg) //filter.RuleSet.Apply方法 //调取Chain.Enqueue方法,接受消息,加入排序 support.Enqueue(msg) //代码在orderer/common/broadcast/broadcast.go ``` #### 3.3.4、向客户端发送响应信息 ```go err = srv.Send(&ab.BroadcastResponse{Status: cb.Status_SUCCESS}) //代码在orderer/common/broadcast/broadcast.go ``` ### 3.4、Broadcast服务端Deliver处理流程 Broadcast服务端Deliver处理流程,即deliver.deliverServer.Handle方法。 ```go func (ds *deliverServer) Handle(srv ab.AtomicBroadcast_DeliverServer) error { for { //接收客户端查询请求 envelope, err := srv.Recv() payload, err := utils.UnmarshalPayload(envelope.Payload) chdr, err := utils.UnmarshalChannelHeader(payload.Header.ChannelHeader) chain, ok := ds.sm.GetChain(chdr.ChannelId) erroredChan := chain.Errored() select { case <-erroredChan: return sendStatusReply(srv, cb.Status_SERVICE_UNAVAILABLE) default: } lastConfigSequence := chain.Sequence() sf := sigfilter.New(policies.ChannelReaders, chain.PolicyManager()) result, _ := sf.Apply(envelope) seekInfo := &ab.SeekInfo{} err = proto.Unmarshal(payload.Data, seekInfo) cursor, number := chain.Reader().Iterator(seekInfo.Start) var stopNum uint64 switch stop := seekInfo.Stop.Type.(type) { case *ab.SeekPosition_Oldest: stopNum = number case *ab.SeekPosition_Newest: stopNum = chain.Reader().Height() - 1 case *ab.SeekPosition_Specified: stopNum = stop.Specified.Number if stopNum < number { return sendStatusReply(srv, cb.Status_BAD_REQUEST) } } for { if seekInfo.Behavior == ab.SeekInfo_BLOCK_UNTIL_READY { select { case <-erroredChan: return sendStatusReply(srv, cb.Status_SERVICE_UNAVAILABLE) case <-cursor.ReadyChan(): } } else { select { case <-cursor.ReadyChan(): default: return sendStatusReply(srv, cb.Status_NOT_FOUND) } } currentConfigSequence := chain.Sequence() if currentConfigSequence > lastConfigSequence { lastConfigSequence = currentConfigSequence sf := sigfilter.New(policies.ChannelReaders, chain.PolicyManager()) result, _ := sf.Apply(envelope) } block, status := cursor.Next() err := sendBlockReply(srv, block) if stopNum == block.Header.Number { break } } err := sendStatusReply(srv, cb.Status_SUCCESS) } } ```
1 下一页