当前位置:首页>区块链文章>区块链推广>区块链学习笔记

区块链学习笔记

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入欢迎使用Markdown编辑器你好! 这是你第一次使用 Markdown编辑器 所展示的欢迎页。如果你想学习如何使用Mar

*区块链更大的不是制造信任,而是让信任产生无损的传递,整个降低社会的摩擦成本,从而提高整个效益。*

区块链技术是通过P2P网络和区块链来实现数据存储的去中心化、不可逆、不可篡改。

区块链主要解决的交易的信任和安全问题,因此它针对这个问题提出了四个技术创新:

①分布式账本

交易记账由分布在不同地方的多个节点共同完成,且每个节点记录的是完整的账本,因此它们都可以参与监督交易合法性,同时可以共同为其作证。

传统分布式存储:将数据按照一定规则分成多份进行存储,通过中心节点往其他备份节点同步数据。

区块链分布式存储:每个节点都按照块链式结构存储完整的数据,每个节点存储的都是独立的、地位相等的,依靠共识机制保证存储的一致性。

没有任何一个节点可以单独记录账本数据,从而避免单一记账人被控制或者贿赂而记假账,也由于节点较多,理论上除非所有节点遭破坏,否则账本不会消失,从而保证账本的数据安全。

②非对称加密和授权技术

存储在区块链上的交易信息是公开的,但是账户身份是高度加密的,只有在数据拥有者授权的情况下才能访问到,从而保证了数据的安全和个人的隐私。

③共识机制 (少数服从多数,人人平等)

记账节点之间怎么达成共识,认定一个记录的有效性,既是认定手段,也是防篡改手段,区块链提出四种共识机制,适用于不同的应用场景,在效率和安全性之间取得平衡。

少数服从多数:不只是节点数,还有计算能力、股权或者其他计算机可以比较的特征量。

人人平等:节点满足条件时,所有节点都有权优先提出共识结果、直接被其他节点认同后并最后有可能成为最终共识结果。

基于这些可信和不可篡改的数据,可以自动化的执行一些预先定义好的规则和条款。

密码学

最开始,比特币更多的是对椭圆曲线公钥密码算法、Ripemd和SHA2数据摘要算法的应用,随着区块链的发展,链上隐私保护成为关注的重点,对称加密、密钥协商、新型密码学技术如环签名、同态加密、零知识证明***(证明者能够在不向验证者提供任何有用的信息的情况下,使验证者相信某个论断是正确的)***、私有账本等开始被广泛应用在隐私保护方案中。1024位的RSA私钥加密已经可以破解。

hash算法

哈希算法是一个单向函数,可以将任意长度的输入数据转化为固定长度的输出数据(哈希值),哈希值就是这段输入数据唯一的数值表现。由于在计算上不可能找到哈希值相同而输入值不同的字符串,因此两段数据的哈希值相同,就可以认为这两段数据也是相同的,所以哈希算法常被用于对数据进行验证。

在区块链中,数据存储在区块里。每个区块都有一个区块头,区块头中存储了一个将该区块所有数据经过哈希算法得到的哈希值,同时,每个区块中还存储了前一个区块的哈希值,这样就形成了区块链。如果想要篡改某一个区块A中的数据,就会导致A的哈希值发生变化,后一个区块B就无法通过哈希值正确地指向A,这样篡改者又必须篡改B中的数据…也就是说,篡改者需要篡改被篡改的区块以及后面的所有区块,才能让所有的节点都接受篡改。

私钥就是随机数或坐标,相当于把金子埋在2256个格子的任意一个里,几乎找不到。

打款人:A 收款人:B

A用B的公钥加密,用自己私钥签名

B用自己私钥解密,用A公钥验证

Merkle树

Merkle树是一种树形结构,在区块链中,Merkle树的叶子节点是区块中数据的哈希值,非叶子节点是其子结点组合后的哈希值,这样由叶子节点开始逐层往上计算,最终形成一个Merkle根,记录在区块的头部,这样就可以保证每一笔交易都无法篡改。

非对称加密

私钥加密,公钥解密。

在区块链中,非对称加密技术主要用于信息加密、数字签名和登录认证。

主要目的不是解密,而是对文件来源的验证,而且,即使文件遭恶意篡改,再用公钥解密,就是无效的,由此可证明信息被改过了,并不是原文件,用这种方式使用公私钥可以证明信息的来源并且有不可否定的特性。只有非对称加密才能 实现不可否认性,但速度较慢且大量使用电力资源及计算资源。

RSA加密算法

RSA的安全基于大数分解的难度。其公钥和私钥是一对大素数(100到200位十进制数或更大)的函数。从一个公钥和密文恢复出明文的难度,等价于分解两个大素数之积(这是公认的数学难题)。

第一步:生成密钥对,即公钥和私钥。

①随机找两个质数P和Q,P与Q越大越安全。

②计算n的欧拉函数φ(n)。

φ(n)表示在小于等于n的正整数中,与n构成互质关系的数的个数(两个整数只有公约数1时,它们的关系叫做互质)。如果n=PQ,P与Q均为质数,则φ(n) = φ(PQ) = φ(P-1)φ(Q-1) = (P-1)(Q-1)

③随机选择一个整数e,条件是1 < e < m,且e与m互质。

④有一个整数d,可以使得e*d除以m的余数为1。

第二步:

*加密生成密文。*

甲向乙发送消息,将密文以utf-8方式编码再转成十进制形成明文(例如“中”以utf-8方式编码为[e4 b8 ad],转为十进制为[228,184,173],则明文为[228,184,173]),甲要使用公钥(n , e)进行加密,要求被加密的数字必须小于n,被加密的数字必须是整数,字符串可以取ASCII或unicode值。假设a为明文,b为密文,按下列公式计算出b,ae% n = b

*解密生成明文。*

乙收到密文用自己的私钥(n,d)解密,解密公式如下,ad % n = b

密文解密后再按utf-8解码为原消息。

对极大整数做因数分解的难度决定了RSA算法的可靠性。

椭圆曲线加密算法(ECC)

​ 是一种基于椭圆曲线数学的公开密钥加密算法,其本质是利用离散对数问题实现加密,相比于RSA,ECC的优势是可以使用更短的密钥,来实现与RSA相当或者更高的安全(例如,一个256 bit的对称密钥必须由大于15 000 bit 的 RSA 来保护,然而,仅用512 bit的ECC非对称密钥就可以提供相等的安全性,因而可有效节约计算成本)。据研究,160位ECC加密安全性相当于1024位RSA加密,210位ECC加密安全性相当于2048位RSA加密,但是缺点是设计困难,实现复杂,如果序列号设计过短,那么安全性并没有想象中完善。(更适用于资源受限的边缘设备)

*什么是椭圆曲线?*

椭圆曲线并不是椭圆的,只是因为椭圆曲线的描述方程,类似于计算一个椭圆周长的方程故而得名。一条椭圆曲线就是一组被y^2^ = x^3^ + ax + b定义的且满足4a^3^ + 27b^2^ ≠ 0 (这个限定条件为了保证曲线不含奇点,即曲线上任何一点都存在切线)

椭圆曲线中的阿贝尔群:

​ ①群中的元素就是椭圆曲线上的点;

​ ②单位元就是无穷处的点0;

​ ③相反数P,是关于X轴对称的另一边的点;

​ ④二元运算规则定义如下:取一条直线上的三点(这条直线和椭圆曲线相交的三点),PQR(皆非零),他们的总和等于0,P+Q+R=0。

*离散对数问题*

ECC算法是在有限域Fp定义公式: Q = k*P,已知大数k和点P的情况下,很容易求点Q,但是已知点P、点Q,却很难求得k,这就是经典的离散对数问题,ECC算法正是利用该特点进行加密,点Q为公钥,大数k为私钥,点P为基点,和RSA最大的实际区别主要是密钥长度。

椭圆曲线加密算法原理

描述一条Fp上的椭圆曲线,常用到六个参量:T=(p,a,b,n,x,y)

(p,a,b)用来确定一条椭圆曲线,p为素数域内点的个数,ab是其中的两个大数;x,y为G基点的坐标,也是两个大数;n为G基点的阶。

以上六个量就可以描述一条椭圆曲线,有时候我们还会用到h(椭圆曲线上所有点的个数p与n相除的整数部分)h≤4,p≠n*h。

利用椭圆曲线进行加密的过程

①选定椭圆曲线Ep(a,b),并取椭圆曲线上的一点,作为基点P。

​ ②选择一个大数k作为私钥,并生成公钥 Q=k P。

​ ③将Ep(a,b)和点Q、P传给用户。

​ ④用户接到信息后,将待传输的明文编码到Ep(a,b)上的一点M,并产生一个随机整数r。

​ ⑤公钥加密(密文C是一个点对):C = { r P , M+rQ }

⑥私钥解密(M+rQ - k(rP),解密结果就是点M),公式如下:

M + rQ – k(rP) = M + r(kP) – k(rP) = M

​ ⑦对点M进行解码就可以的到明文

如今ECC应用范围很广,在TLS、区块链、SM2国密算法、证书、银行政府机构等许多方面都有大量应用。

Curve25519加密算法

Curve25519 是目前最高水平的 Diffie-Hellman函数,适用于广泛的场景,由Daniel J. Bernstein教授设计。在密码学中,Curve25519是一个椭圆曲线提供128位安全性,设计用于椭圆曲线Diffie-Hellman(ECDH)密钥协商方案。它是最快的ECC曲线之一,并未被任何已知专利所涵盖。给定一个用户的32字节密钥,curve25519计算该用户的32字节公钥。给定该用户的32字节密钥和另一个用户的32字节公钥,curve25519计算一个32字节的共享密钥提供给这两个用户使用。然后可以使用这个秘密对两个用户进行身份验证和信息加密。

https://blog.csdn.net/u011897062/article/details/89633193

对称加密

****优点:****①更容易配置和撤销 ②使用时更容易保护 ③更快的执行速度 ④降低功耗、内存和CPU使用率 (与RSA和ECC相比) ⑤降低每个密钥的成本

****缺点:****密钥数量随着参与方的增长而呈指数级增长

高级加密标准(AES)

RC2

零知识密钥

在零知识密码系统中,证明者能够向验证者证明其知道秘密,而不必在操作阶段的任何时间泄露秘密。验证者可以提问以确认证明者确实知道秘密,但验证者或任何第三方都无法发现有关该秘密的信息。

实现零知识性,允许你安全地向他人进行证明。交互的消息能构成一个证明(仍然体现了传统证明的精髓)而它们本身不泄漏“断言为真”之外的任何知识。这里的“知识”可以理解为“计算能力”,证明是“零知识的”意味着整个证明过程没有增加验证者的计算能力(即验证者之前无法解决的问题在证明完成之后仍然无法解决)。这个性质保证了交互完成后验证者只知道被证明的断言为真,但他并不知道怎么转而向其他人证明这一断言,它的代价是会产生一些微小的错误。
这里一个比较精确一点的例子就是向红绿色盲来证明两个球着色不同(一个红一个 绿):视觉正常的证明者持有的传统证明/证据是眼里看到的不同颜色,他先将两个球分别放在色盲的两只手中,记住左右手中的颜色;色盲将手放背后,脑子里随机决定是否在背后交换手中的球,然后将双手握球展示给证明者并问他自己是否刚才在背后交换了手中的球,证明者通过对比之前色盲两手中球的颜色来回答他的问题。这一交互证明体现了上述传统证明系统的两点精髓,对于第二点, 这里带来了1/2的错误概率,即对于错误的断言(即两个球颜色相同),证明者仍能以1/2的概率骗过验证者,不过这可以重复多次来降低这一概率。零知识在这里显而易见:色盲在交互结束后除了相信他手中球是颜色不同的之外并没有得到任何额外的知识。

零知识证明一个显然的密码学应用就是身份认证。如你可以随机挑选两个素数p和q,在“分解整数是困难的”假设下,这构成了一个身份认证系统:验证方在证明完成后没有得到任何有关两个素因子的知识。

隐私计算

隐私计算是一类技术统称,旨在保护数据本身不对外泄露的前提下,实现数据分析计算。

隐私计算针对不同的应用场景、信任环境和需求,将不同技术、算法、接口集成在一个平台上,并结合人工智能、机器学习、区块链等跨学科技术,为用户提供综合的解决方案,使得“不分享数据、但分享数据的价值”成为可能。

隐私计算可区分数据承载的具体信息和计算价值,厘清数据使用的“权、责、利”,使得数据可以作为资产流通与变现。

关键技术

隐私计算的关键技术包括联邦学习、安全多方计算、机密计算、差分隐私、同态加密。其中,联邦学习、多方安全计算和机密计算目前应用最广。

区块链学习笔记

联邦学习目前商业化更为成熟,适用于机器学习建模;多方安全计算目前支持的功能较少,适用于统计分析、查询等基本功能,但安全性更高;机密计算基于可信任硬件,可以减少对特有软件的信任依赖,但受到硬件采购成本、对硬件厂商信任度等因素的制约。

隐私计算将贯穿整个IaaS基础算力层、BaaS、SaaS服务层。

算力层,隐私计算与云计算作为重要的IaaS基础设施,同时和AI存在融合空间,可以为数据交换、存储和计算协作的可信环境提供算法支撑

BaaS/SaaS层,隐私计算在数据价值挖掘环节可以发挥巨大作用,在金融、医疗、科学研究、社会征信、供应链金融、防伪溯源、社会治理等领域提供基于数据分析的应用服务。

应用场景

隐私计算已在金融、政府、营销、医药等场景初步商业落地,具体应用模式包括跨域分布式身份的认证、数据授权分享、区块链钱包管理与隐私交易、数据安全匹配、多方联合建模、安全建模应用等。

**1)金融场景:**主要应用包括数字营销、风控与反欺诈、存客激活与信用分析等。

金融行业数据交易多,对风控要求高;客户付费能力强,数字化程度高,因此是隐私计算的最佳切入点。

**2)政府场景:**主要应用涉及能源、交通、规划、环保等多行业和多部门。

政务领域具有较完备的数据基础,但需要打通并共享各部门数据,才能支撑各项应用。

**3)营销场景:**主要应用在精准获客等环节,包括消费者的信息、购买能力等,以便为不同的消费人群提供定制化的服务。

**4)医疗场景:**主要应用在精准医学、AI制药的核心要素。

医疗机构中的病例数据是最重要的隐私数据,但是单个医疗机构的数据样本不足以支撑大规模的模型训练,需要多方共享数据。

随着三大运营商打造大数据安全开放平台,地方政府安全开放共享政务数据,金融机构需要在风控、营销场景中进行大数据内外融合,大数据安全计算与数据服务将迎来极佳机会点。

联邦学习

区块链与联邦学习结合的学习网址:

https://blog.csdn.net/sgentle/article/details/116139971

共识机制

所谓共识机制,就是区块链中的节点,其中包括诚实节点和恶意节点,如何写入下一个区块达成共识。

把出现故障但不会伪造信息的情况称为“非拜占庭错误”或“故障错误”;伪造信息恶意响应的情况称为“拜占庭错误”。

由 Eirc Brewer 提出,Lynch 等人证明的 CAP 定理为解决分布式系统中的一致性问题提供了思路。CAP 定理的描述如下:在分布式系统中,一致性可用性和分区容错性三者不可兼得。这三个术语的解释如下:

  • 一致性(Consistency):所有节点在同一时刻拥有同样的值(等同于所有节点访问同一份最新的数据副本
  • 可用性(Availability):每个请求都可以在有限时间内收到确定其是否成功的响应
  • 分区容错性(Partition tolerance):分区是指部分节点因为网络原因无法与其他节点达成一致。分区容错性是指由网络原因导致的系统分区不影响系统的正常运行。例如,由于网络原因系统被分为 A, B, C, D 四个区,A, B 中的节点无法正常工作,但 C, D 组成的分区仍能提供正常服务。

工作量证明(POW)proof of work

可以容纳一半以下算力时的任何错误的发生,但是对资源消耗高,共识时间慢,常用于比特币、以太坊等初期公链项目中。出块慢、吞吐量小、耗电量大。(导致人们构建越来越大型的挖矿设备,电力消耗严重,促进矿池的产生,让区块链变得中心化)

PoW 机制的大致流程如下:

  1. 向所有节点广播新交易和一个数学问题
  2. 最先解决了数学问题的节点将交易打包成区块,对全网广播
  3. 其他节点验证广播区块的节点是否解决了数学问题(完成了一定的工作量),验证通过则接受该区块,并将该区块的哈希值放入下一个区块中,表示承认该区块

由于在 PoW 机制中,区块的产生需要解决一个数学问题,也就是所谓的挖矿,这往往要消耗较大的算力和电力,因此节点们倾向于在最长的链的基础上添加区块,因为如果节点想在自己的链上添加新的区块,那么就需要重新计算 1 个或 n n n 个这样的数学问题(每添加一个区块就需要计算一个)。因此在比特币中最长的链被认为是合法的链,这样节点间就形成了一套“共识”。

PoW 机制的优点是完全去中心化,缺点是需要依赖数学运算,资源的消耗会比其他的共识机制高,可监管性弱,同时每次达成共识需要全网共同参与运算,性能较低。

权益证明(POS)proof of stake

POS原理的核心概念为币龄,即持有货币的时间,例如有10个货币,持有90天,即拥有900币天的币龄,使用货币即意味着币龄的销毁。在POS中有一种特殊的交易成为利息币,即持有人可以销毁币龄获得利息,同时获得为网络产生区块以及POS造币的优先权。可以容纳一半以下算力时的任何错误的发生,减少资源消耗,效率提高,但是权益越高权力越大,最终会走向集中式发展。通过选举的形式,其中任意节点被随机选择来验证下一个区块,验证者也不是完全随机选择的,要成为验证者,节点需要在网络中存入一定数量的货币作为权益,可以将这理解为保证金,权益份额大小决定被选为验证者的几率,从而得以创建下一个区块,如果验证者通过了一些欺诈性的交易,他们将失去一部分权益,只要权益比交易费高,就是可行的。

PoS 针对 PoW 的缺点做出了改进。PoS 要求参与者预先放置一些货币在区块链上用于换取“股权”,从而成为验证者(Validator),验证者具有产生区块的权利。PoS 机制会按照存放货币的量和时间给验证者分配相应的利息,同时还引入了奖惩机制,打包错误区块的验证者将失去他的股权——即投入的货币以及产生区块的权利。PoS 机制的大致流程如下:

  1. 加入 PoS 机制的都是持币人,称为验证者
  2. PoS 算法根据验证者持币的多少在验证者中挑选出一个给予产生区块的权利
  3. 如果一定时间内没有产生区块,PoS 就挑选下一个验证者,给予产生区块的权利
  4. 如果某个验证者打包了一份欺诈性交易,PoS 将剥夺他的股权

PoS 的优点在于:

  1. 引入了利息,使得像比特币这样发币总数有限的通货紧缩系统在一定时间后不会“无币可发”
  2. 引入了奖惩机制使节点的运行更加可控,同时更好地防止攻击
  3. 与 PoW 相比,不需要为了生成新区块而消耗大量电力和算力
  4. 与 PoW 相比,缩短了达成共识所需的时间

由于 PoS 机制需要用户已经持有一定数量的货币,没有提供在区块链应用创立初始阶段处理数字货币的方法,因此使用 PoS 机制的区块链应用会在发布时预先出售货币,或在初期采用 PoW,让矿工获得货币后再转换成 PoS,例如以太坊现阶段采用的是 PoW 机制,在第四阶段“宁静”(Serenity)中将过渡到 PoS。

股份授权证明算法(DPOS)delegated proof of stake

DPOS既能解决POW在挖矿过程中产生的大量能源消耗的问题,也可以解决POS权益分配下可能产生的信任天平偏颇的问题。DPOS是由被社区选举的可信账户**(超级节点)**来创建区块。对恶意节点的惩罚:不按排程产生区块的超级节点将在下一轮被投票剔除,被没收缴纳的保证金。能耗与网络运行成本低、理论上更加去中心化、较快的确认速度、坏节点不能及时处理,只有经过选举才能清除坏节点、小散投票积极性不高、依赖代币。应用于比特股(Bitshare)密码货币。

DPoS 有更快的区块产生和确认速度,每个区块产生的时间仅为 10 秒,交易的确认时间仅为 1 分钟(6 -10 个节点确认),这与比特币运行机制中的 10 分钟产生一个区块,确认一笔交易需要一个小时时间来确认的速度大大提升。但是其缺点也十分明显,第一,网络中节点参与选举的参与度大幅度降低,因为投票选举需要耗费时间和精力,人的惰性使之不愿花费时间而直接获取利益。第二,对于网络中恶意节点的破坏阻止难度更大,给整个网络安全运行安全造成极大的威胁。

轮询算法

区块链上链设备的选择可根据轮询或系统规则匹配的方式进行区 块信息的上链,而避免通过 Pow 和 PoS 机制竞争上链,以减少计算和通信资源的过度浪费,有效保障 业务系统的可靠运行。

轮询算法是最简单的一种负载均衡算法。它的原理是把来自用户的请求轮流分配给内部的服务器:从服务器1开始,直到服务器N,然后重新开始循环。

算法的优点是其简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度。假设有N台服务器:S = {S1, S2, …, Sn},一个指示变量i表示上一次选择的服务器ID。变量i被初始化为N-1。该算法的伪代码如下:

j = i;do{j = (j + 1) mod n;i = j;return Si;} while (j != i);return NULL;

轮询算法假设所有服务器的处理性能都相同,不关心每台服务器的当前连接数和响应速度。当请求服务间隔时间变化比较大时,轮询算法容易导致服务器间的负载不平衡。所以此种均衡算法适合于服务器组中的所有服务器都有相同的软硬件配置并且平均服务请求相对均衡的情况。

加权轮询算法(WeightedRound-Robin)

轮询算法并没有考虑每台服务器的处理能力,实际中可能并不是这种情况。由于每台服务器的配置、安装的业务应用等不同,其处理能力会不一样。所以,加权轮询算法的原理就是:根据服务器的不同处理能力,给每个服务器分配不同的权值,使其能够接受相应权值数的服务请求。

首先看一个简单的Nginx负载均衡配置。

http { upstream cluster { server a weight=1; server b weight=2; server c weight=4; } ...} 

按照上述配置,Nginx每收到7个客户端的请求,会把其中的1个转发给后端a,把其中的2个转发给后端b,把其中的4个转发给后端c。

加权轮询算法的结果,就是要生成一个服务器序列。每当有请求到来时,就依次从该序列中取出下一个服务器用于处理该请求。比如针对上面的例子,加权轮询算法会生成序列{c, c, b, c, a, b, c}。这样,每收到7个客户端的请求,会把其中的1个转发给后端a,把其中的2个转发给后端b,把其中的4个转发给后端c。收到的第8个请求,重新从该序列的头部开始轮询。

总之,加权轮询算法要生成一个服务器序列,该序列中包含n个服务器。n是所有服务器的权重之和。在该序列中,每个服务器的出现的次数,等于其权重值。并且,生成的序列中,服务器的分布应该尽可能的均匀。比如序列{a, a, a, a, a, b, c}中,前五个请求都会分配给服务器a,这就是一种不均匀的分配方法,更好的序列应该是:{a, a, b, a, c, a, a}。

网址: [负载均衡之加权轮询算法 – -零 – 博客园 (cnblogs.com)](https://www.cnblogs.com/-wenli/p/11664191.html#:~:text=轮询算法是最简单的一种负载均衡算法。,它的原理是把来自用户的请求轮流分配给内部的服务器:从服务器1开始,直到服务器N,然后重新开始循环。 算法的优点是其简洁性,它无需记录当前所有连接的状态,所以它是一种无状态调度。)

拜占庭容错(PBFT)

是联盟链普遍使用的共识算法,可以容纳三分之一的错误(3f+1个节点时,容纳f个节点出错),效率相对更高,但是节点数量受限,规模不能过大。要求所有节点之间两两通信,因此要求节点不宜过多,通常是几十个。效率高、吞吐量高、节能、可拓展性及去中心化较弱、容错性较低。PBFT算法的节点数量是固定的,节点身份提前确定,无法动态添加或删除,只能适用于节点数目固定的联盟链或私有链场景中。一般适用于对强一致性有要求的私有链和联盟链场景,但如果结合DPOS节点代表选举规则,也可以应用于公有链,并且可以在一个不可信的网络里解决拜占庭容错问题。在Hyperledger Fabric项目中,共识模块被设计成可插拔的模块,支持像PBFT、Raft等共识算法。

拜占庭将军问题是分布式网络中的通信容错问题,可以描述为:

一组拜占庭将军各领一支队伍共同围困一座城市。各支军队的行动策略限定为进攻或撤离两种。因为部分军队进攻而部分军队撤离可能会造成灾难性的后果,因此各将军决定通过投标来达成一致策略,即“共进退”。因为各将军位于城市不同方向,他们只能通过信使互相联系。在投票过程中每位将军都将自己的选择(进攻或撤退)通过信使分别通知其他所有将军,这样一来每位将军根据自己的投票和其他所有将军送来的信息就可以知道共同投票的结果,进而做出行动。

拜占庭将军的问题在于,将军中可能出现叛徒。假设3名将军中有1名叛徒,2名忠诚将军一人投进攻票,一人投撤退票,这时叛徒可能会故意给投进攻的将军投进攻票,而给投撤退的将军投撤退票。这就导致一名将军带队发起进攻,而另外一名将军带队撤退。

另外,由于将军之间通过信使进行通讯,即使所有将军都忠诚,也不能排除信使被敌人截杀,甚至信使叛变等情况。

假设存在叛变将军或信使出问题等情况,如果忠诚将军仍然能够通过投票来决定他们的战略,便称系统达到了拜占庭容错(Byzantine Fault Tolerance)

拜占庭问题对应到区块链中,将军就是节点,信使就是网络等通信系统,要解决的是存在恶意节点、网络错误等情况下系统的一致性问题。

简化版拜占庭容错(RAFT)

{先选出领导节点}{主要阶段:①领导者选举②同步日志}不能容纳拜占庭错误,基于联盟链与参与方之间已有一定的信任基础,常用于联盟链中。 在日常中更多的是计算机故障挂掉了或者网络通信问题无法传递信息,这种情况不考虑计算机之间发送恶意消息。每个系统节点有三种状态:Follower、Candidate、Leader。实现Raft算法两个最重要的事是:选主和复制日志。

Paxos算法(Paxos)

Paxos算法是基于消息传递且具有高度容错特性的一致性算法,是目前公认的解决分布式一致性问题最有效的算法之一,其解决的问题就是在分布式系统中如何就某个值(决议)达成一致。Paxos算法的前提假设是不存在拜占庭将军问题,即:信道是安全的(信道可靠),发出的信号不会被篡改,因为Paxos算法是基于消息传递的。因此在对一致性的研究过程中,都往往假设信道是可靠的,而事实上,大多数系统都是部署在一个局域网中,因此消息被篡改的情况很罕见;另一方面,由于硬件和网络原因而造成的消息不完整问题,只需要一套简单的校验算法即可。因此,在实际工程中,可以假设所有的消息都是完整的,也就是没有被篡改。

Algorand 共识算法:

https://blog.csdn.net/omnispace/article/details/79653972?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161793563716780269893635%2522%252C%2522scm%2522%253A%252220140713.130102334…%2522%257D&request_id=161793563716780269893635&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allsobaiduend~default-2-79653972.pc_search_result_no_baidu_js&utm_term=algorand%E5%85%B1%E8%AF%86%E7%AE%97%E6%B3%95

P2P网络

P2P (Peer to Peer)是一种分散的网络通信模型,其中,对等节点是彼此连接的计算机平台中的,对等节点之间的通信无需中央平台(服务器)即可完成。
换句话说,网络中的每个对等节点既是服务器又是客户端。使用 P2P 通信的优点是可以保护用户隐私,降低服务器成本等。
计算机加入对等网络的唯一要求是 Internet 网络连接和 P2P 软件。常见的 P2P软件程序包括 Kazaa、Limewire、BearShare、Morpheus 和 Acquisition。这些程序连接到 P2P 网络,例如 Gnutella,它使计算机可以访问网络上成千上万的其他平台。

连接到网络后,P2P 软件允许您在其他人的计算机上搜索文件。同时,网络上的其他用户可以在您的计算机上搜索文件,但通常只能在您指定共享的单个文件夹中搜索。P2P 网络使文件共享变得容易和方便,同时也导致了许多软件盗版和非法音乐下载。

通过 P2P 网络下载相同文件时,处理流程和集中式有所不同。在这里,用户必须预安装对等软件,当用户下载文件时,该软件会创建一个对等用户的虚拟网络,该文件是从网络中已经具有该对等点的其他对等点传输来的比特数中接收到的。在接收到数据的同时,文件也被发送到网络中需要该资源的其他的对等方。

对等网络体系结构中的每个对等方都有相同的职责,每个对等方都是服务器和客户端。对等网络分类为三种类型:非结构化、结构化和混合网络。
在非结构化对等网络上没有覆盖网络设计的特定结构。它们由节点相互之间随机连接形成。因为没有结构,所以非结构化的对等网络很容易构建,但效率不高。

P2P 网络有许多便利的同时,其缺点也不容忽视。例如,数据没有组织到特定的共享区域中,有时可能很难找到文件;网络中的数据没有安全保障。因此P2P 网络的使用需要根据自身需求来使用。

以太坊

以太坊简介

以太坊是目前使用最广泛的支持完备应用开发的共有区块链系统。

和比特币不同,比特币只适合加密数字货币场景,不具备图灵完备性,也缺乏保存实时状态的账户概念,以及存在 PoW 机制带来的效率和资源浪费的问题,而以太坊作为区块链2.0的代表,目标是扩展智能合约和建立一个去中心化应用平台,具有图灵完备的特性、更高效的共识机制、支持智能合约等多种应用场景,使得开发者能够很方便地在以太坊上开发出基于区块链的应用。

以太坊的特点

以太坊团队和外界对以太坊的描述都是“世界计算机”,这代表它是一个开源的、全球的去中心化计算架构。它执行称为智能合约的程序,并使用区块链来同步和存储系统状态,以及使用名为以太币的加密数字货币来计量和约束执行操作的资源成本。同时,以太坊提供了一系列的接口,使得开发者能够通过以太坊来开发去中心化 Web 应用DApps。

幽灵协议

幽灵协议的英文是“Greedy Heaviest Observed Subtree\” (GHOST) protocol,

区块链学习笔记

假设目前以太坊区块链中的区块高度(区块链上的区块个数)为6,现在产生了一笔新的交易,矿工A先将该笔交易打包成了区块 Block 7,在矿工A将 Block 7 广播到其他节点的这段时间里,矿工B和矿工C又分别产生了 Block 8 和 Block 9。Block 7、Block 8、Block 9 都指向 Block 6,即 Block 6 是他们的父区块。由于 Block 7 是最先产生的,因此 Block 7 被认为是有效区块,Block 8 和 Block 9 就是叔区块(作废区块)。

区块链学习笔记

现在链上的区块高度为7,在这基础上又产生了新的交易,并被打包成了 Block 10。在以太坊中,Block 10 除了可以引用它的父区块 Block 7 外,还可以引用叔区块 Block 8 和 Block 9。并且,Block 8 和 Block 9 的矿工会因此获得一笔奖励,称为叔块奖励,Block 10 的矿工除了基础奖励之外,由于引用了叔区块,还会获得一笔额外的叔块引用奖励

幽灵协议是以太坊的一大创新。由于在比特币中的出块时间被设计为10分钟,而以太坊为了提高出块速度,将出块时间设计为12秒(实际14~15秒左右),这样的高速出块意味着高速确认,高速确认会带来区块的高作废率低安全性。因为区块需要花一定的时间才能广播至全网,如果矿工 A 挖出了一个区块,而矿工 B 碰巧在 A 的区块扩散至 B 之前挖出了另一个区块,矿工 B 的区块就会作废并且没有对区块链的网络安全做出贡献。此外,这样的高速确认还会带来中心化的问题:如果 A 拥有全网 30% 的算力而 B 拥有 10% 的算力,那么 A 将会在 70% 的时间内都在产生作废区块,而 B 在 90% 的时间内都在产生作废区块,这样,B 永远追不上 A,后果是 A 通过其算力份额拥有对挖矿过程实际上的控制权,出现了算力垄断,弱化了去中心化。

幽灵协议正是为了解决上述问题而引入的,协议的主要内容如下:

  • 计算最长链时,不仅包括当前区块的父区块和祖区块,还包括祖先块的作废的后代区块(叔区块),将它们综合考虑来计算哪一个区块拥有支持其的最大工作量证明。这解决了网络安全性的问题
  • 以太坊付给以“叔区块”身份为新块确认作出贡献的废区块87.5%的奖励(叔块奖励),把它们纳入计算的“侄子区块”将获得奖励的12.5%(叔块引用奖励)。这就使得即使产生作废区块的矿工也能够参与区块链网络贡献并获得奖励,解决了中心化倾向的问题
  • 叔区块最深可以被其父母的第二代至第七代后辈区块引用。这样做是为了:
    • 降低引用叔区块的计算复杂性
    • 过多的叔块引用奖励会剥夺矿工在主链上挖矿的激励,使得矿工有转向公开攻击者链上挖矿的倾向(即公开攻击者可能会恶意产生大量作废区块,无限引用将会诱使矿工转移到攻击者的链上,从而抛弃合法的主链)
    • 计算表明带有激励的五层幽灵协议即使在出块时间为15s的情况下也实现了了95%以上的效率,而拥有25%算力的矿工从中心化得到的益处小于3%

以太坊的组成部分

在以太坊中,包括了 P2P 网络、共识机制、交易、状态机、客户端这几个组成部分。

  • P2P 网络:在以太坊主网上运行,可通过TCP端口30303访问,并运行称为 ÐΞVp2p 的协议。
  • 共识机制:以太坊目前使用名为 Ethash 的 POW 算法,计划在将来会过渡到称为 Casper 的 POS 算法。
  • 交易:以太坊中的交易本质上是网络消息,包括发送者、接收者、值和数据载荷(payload)。
  • 状态机:以太坊的状态转移由以太坊虚拟机(Ethereum Virtual Machine,EVM)处理,EVM 能够将智能合约编译成机器码并执行。
  • 客户端:用于用户和以太坊进行交互操作的软件实现,最突出的是 Go-Ethereum(Geth) 和 Parity。

以太坊中的概念

  • 账户:以太坊中的账户类似于银行账户、应用账户,每个账户有一个20字节的地址。账户又分为普通账户(又叫外部账户,External Owned Account, EOA)和合约账户(Contract)。普通账户是由以太坊使用者创建的账户,包含地址、余额和随机数;合约账户是创建智能合约时建立的账户,包含存储空间和合约代码
  • 状态:状态是由账户和两个账户之间价值的转移以及信息的状态转换构成的
  • 地址:地址是一个账户 ECDSA 公钥的 Keccak 散列最右边的160位,通过地址可以在以太坊上接收或发送交易。在 Etherscan 上,可以通过地址来查询一个账户的信息
  • 交易:以太坊中的交易不仅包括发送和接收以太币,还包括向合约账户发送交易来调用合约代码、向空用户发送交易来生成以交易信息为代码块的合约账户
  • Gas: Gas 是以太坊中的一种机制,用于执行智能合约或交易操作的虚拟燃料。由于以太坊是图灵完备的,为了避免开发者无意或恶意编写出死循环等浪费资源或滥用资源的情况,以太坊中的每一笔交易都需支付一定的 Gas (燃料费),即需支付一定的以太币作为 Gas。Gas 的金额通常是由交易的发起者指定并支付的
  • 挖矿:和比特币类似,以太坊同样通过挖矿来产生区块。在以太坊目前的 PoW 机制下,每当一笔交易发出并广播,就会吸引矿工来将该交易打包成区块。每产生一个区块都会有一笔固定奖励给矿工,目前的固定奖励是3个以太。同时,区块中所有操作所需的 Gas 也会作为奖励给矿工。与比特币不同的是,以太坊中产生叔块的矿工可能会获得叔块奖励,引用叔块的矿工会获得叔块引用奖励
  • DApp(去中心化应用):通过智能合约,开发者能够设计想要的逻辑,相当于是网站的后端。而 DApp 则相当于是一个完整的网站(前端+后端),因此 DApp = 智能合约 + Web 前端。以太坊提供了一个名为 web3.js 的 Javascript 库,通过 web3.js 可以实现 Web 与以太坊区块链的交互和与智能合约的交互,方便开发者创建 DApp

以太坊交易的数据结构

在以太坊网络中,交易执行属于一个事务。具有原子性、一致性、隔离性、持久性特点。

  • 原子性: 是不可分割的最小执行单位,要么做,要么不做。
  • 一致性: 同一笔交易执行,必然是将以太坊账本从一个一致性状态变到另一个一致性状态。
  • 隔离性: 交易执行途中不会受其他交易干扰。
  • 持久性: 一旦交易提交,则对以太坊账本的改变是永久性的。后续的操作不会对其有任何影响。

以太坊交易的本质是由外部拥有的账户发起的签名消息,由以太坊网络传输,并被序列化后记录在以太坊区块链上,交易是唯一可以触发状态更改或导致合约在EVM中执行的事物

交易的数据结构

以太坊的数据结构主要可以分为四部分:noncegas、交易目标和消息(主要部分)、交易签名

区块链学习笔记

开头是一个 uint64 类型的数字,称之为随机数。用于撤销交易、防止双花和修改以太坊账户的 Nonce 值。

第二部分是关于交易执行限制的设置,gas 为愿意供以太坊虚拟机运行的燃料上限。 gasPrice 是愿意支付的燃料单价。gasPrcie * gas 则为愿意为这笔交易支付的最高手续费。

第三部分是交易发送者输入以太坊虚拟机执行此交易的初始信息: 虚拟机操作对象(接收方 To)、从交易发送方转移到操作对象的资产(Value),以及虚拟机运行时入参(input)。其中 To 为空时,意味着虚拟机无可操作对象,此时虚拟机将利用 input 内容部署一个新合约

第四部分是交易发送方对交易的签名结果,可以利用交易内容和签名结果反向推导出签名者,即交易发送方地址。以上总结如下:

  • nonce:由发起人EOA发出的序列号,用于防止交易消息重播。
  • gas price:交易发起人愿意支付的gas单价(wei)。
  • start gas:交易发起人愿意支付的最大gas量。
  • to:目的以太坊地址。
  • value:要发送到目的地的以太数量。
  • data:可变长度二进制数据负载(payload)。
  • v,r,s:发起人EOA的ECDSA签名的三个组成部分。
  • 交易消息的结构使用递归长度前缀(RLP)编码方案进行序列化,该方案专为在以太坊中准确和字节完美的数据序列化而创建。

交易中的nonce

按以太坊黄皮书的定义, nonce是一个标量值,它等于从这个地址发送的交易数,或者对于关联code的帐户来说,是这个帐户创建合约的数量。因此nonce便有以下特征:

  • nonce不会明确存储为区块链中帐户状态的一部分。相反,它是通过计算发送地址的已确认交易的数量来动态计算的。
  • nonce值还用于防止错误计算账户余额。nonce强制来自任何地址的交易按顺序处理,没有间隔,无论节点接收它们的顺序如何。
  • 使用nonce确保所有节点计算相同的余额和正确的序列交易,等同于用于防止比特币“双重支付”(“重放攻击”)的机制。但是,由于以太坊跟踪账户余额并且不单独跟踪 UTXO ,因此只有在错误地计算账户余额时才会发生“双重支付”。nonce机制可以防止这种情况发生。

并发和nonce

以太坊是一个允许操作(节点,客户端,DApps)并发的系统,但强制执行单例状态。例如,出块的时候只有一个系统状态。假如我们有多个独立的钱包应用或客户端,比如 MetaMask 和 Geth,它们可以使用相同的地址生成交易。如果我们希望它们都够同时发送交易,该怎么设置交易的nonce呢?一般有以下两种做法:

  • 用一台服务器为各个应用分配nonce,先来先服务——可能出现单点故障,并且失败的交易会将后续交易阻塞。
  • 生成交易后不分配nonce,也不签名,而是把它放入一个队列等待。另起一个节点跟踪nonce并签名交易。同样会有单点故障的可能,而且跟踪nonce和签名的节点是无法实现真正并发的。

交易中的gas

Gas 中译是:瓦斯、汽油,代表一种可燃气体。 这形象地比喻以太坊的交易手续费计算模式,不同于比特币中直接支付比特币作为转账手续费, 以太坊视为一个去中心化的计算网络,当你发送Token、执行合约、转移以太币或者在此区块上干其他的时候,计算机在处理这笔交易时需要进行计算消耗网络资源,这样你必须支付燃油费购买燃料才能让计算机为你工作。最终燃料费作为手续费支付给矿工。

因为手续费等于gasPrice * gasUsed,用户在转账,特别是执行智能合约时 gasUsed 无法提前预知。 这样存在一个风险,当用户的交易涉及一个恶意的智能合约,该合约执行将消耗无限的燃料, 这样会导致交易方的余额全部消耗(恶意的智能合约有可能是程序Bug,如合约执行陷入一个死循环)。

为了避免合约中的错误引起不可预计的燃料消耗,用户需要在发送交易时设定允许消耗的燃料上限,即 gasLimit。 这样不管合约是否良好,最坏情况也只是消耗 gasLimit 量的燃料。

然而,一笔交易所必须支付的燃料已经在区块中通过该交易已执行的计算量记录。 如果你不想支出太多燃料,而故意设置过低的 gasLimit 是没太多帮助的。 你必须支付足够燃料来支付本交易所必要的计算资源。如果交易尚未执行完成,而燃料已用完, 将出现一个 Out of Gas 的错误。特别注意的是,即使交易失败,你也必须为已占用的计算资源所支付手续费。 比如,你通过合约给 TFBOYS 投票,设置 gasPrice=2 gwei,gasLimit=40000(实现投票需要40001的燃料开销), 最终你投票失败且仍然需要支付 40000*2 gwei= 80000 gwei= 0.00008 ETH。

另外,如果最终 gasUsed 低于 gasLimit,即燃料未用完。则剩余燃料(gasLimit – gasUsed )将在交易后退还给你。 比如你发送 1 Ether 到另一个账户B,设置 gas limit 为 400000,将有 400000 – 21000 返回给你。

注意:21000 是标准转账交易的gasUsed。因此一笔标准的转账交易你可以设置 gasLimit 为21000

以太坊账户

对比比特币的UTXO余额模型,以太坊使用“账户”余额模型。 以太坊丰富了账户内容,除余额外还能自定义存放任意多数据。 并利用账户数据的可维护性,构建智能合约账户。下面我们首先将比特币的UTXO余额模型与以太坊账户进行比较,说明其各自的优缺点以及适用性。

比特币UTXO

UTXO是 Unspent Transaction Output的缩写,意思是**未花费的输出,**可以简单理解为还没有用掉的收款。比如韩梅梅收到一笔比特币,她没有用掉,这笔比特币对她来说就是一个UTXO。关于UTXO的具体介绍可以查看这篇文章。

**UTXO 核心设计思路是:它记录交易事件,而不记录最终状态。**要计算某个用户有多少比特币,就要对其钱包里所有的UTXO求和,得到结果就是他的持币数量。UTXO模型在转账交易时,是以UTXO为单位的,也就是说在支付时,调用的是整数倍UTXO,比如1个UTXO,3个UTXO,没有0.5个UTXO的说法。

  • 比特币在基于UTXO的结构中存储有关用户余额的数据,系统的整个状态就是一组UTXO的集合,每个UTXO都有一个所有者和一个面值(就像不同的硬币),而交易会花费若干个输入的UTXO,并根据规则创建若干个新的UTXO
  • 每个引用的输入必须有效并且尚未花费,对于一个交易,必须包含有每个输入的所有者匹配的签名,总输入必须大于等于总输出值。所以系统中用户的余额是用户具有私钥的UTXO的总值

以太坊账户

为什么以太坊不用UTXO呢?显然是因为麻烦,以太坊的做法更符合直觉,以太坊中的状态就是系统中所有账户的列表,每个账户都包含了一个余额和以太坊特殊定义的数据(代码和内部存储)。如果发送账户有足够多的余额来进行支付,则交易有效,在这种情况下发送账户先扣款,而收款账户将记入这笔收入。如果接受账户有相关代码,则代码会自动运行,并且它的内部存储也可能被更改,或者代码还可能向其他账户发送额外的消息,这就会导致进一步的借贷资金关系。

优缺点比较

比特币UTXO的优点

  • 更高程度的隐私:如果用户为他们收到的每笔交易使用新地址,那么通常很难将账户互相链接。这很大程度上适用于货币,但不太适用于任何dapps,因为dapps通常涉及跟踪和用户绑定的复杂状态,可能不存在像货币那样简单的用户状态划分方案
  • 潜在的可扩展性:UTXO在理论上更符合可扩展性要求,因为我们只需要依赖拥有UTXO的那些人去维护基于Merkle树的所有权证明就够了,即使包括所有者在内的每个人都决定忘记该数据,那么也只有所有者受到对应的UTXO的损失,不影响接下来的交易。而在账户模式中,如果每个人都丢失了与账户相对应的Merkle树的部分,那将会使得和该账户有关的消息完全无法处理,包括发币给它。

以太坊账户模式的优点

  • 可以节省大量空间:不将UTXOs分开存储,而是合成一个账户;每个交易只需要一个输入、一个签名并产生一个输出
  • 更好的可替代性:货币本质上都是同质化、可替代的;UTXO的设计使得货币从来源分成了“可花费”和“不可花费”两类,这在实际应用中很难有对应模型
  • 更加简单:更容易编码和理解,特别是设计复杂脚本的时候,UTXO的脚本逻辑复杂时更令人费解
  • 便于维护持久轻节点:只要沿着特定方向扫描状态树,轻节点 可以很容易地随时访问账户相关的所有数据。而UTXO地每个交易都会使得状态引用发生改变,这对应节点来说长时间运行Dapp会有很大压力

区块链学习笔记

外部账户(EOA)

外部账户是由人来控制的,也就是常规理解的普通账户,外部账户包含以太币余额,主要作用就是发送交易(是广义的交易,包括转币和触发合约代码),是由用户私钥控制的,没有关联代码,所有在以太坊上交易的发起者都是外部账户。

外部账户特点总结:

  1. 拥有以太余额。
  2. 能发送交易,包括转账和执行合约代码。
  3. 被私钥控制。
  4. 没有相关的可执行代码。

合约账户

合约账户有时也叫内部账户,有对应的以太币余额和关联代码,它是由代码控制的,可以通过交易或来自其他合约的调用消息来触发代码执行,执行代码时可以操作自己的存储空间,也可以调用其他合约

合约账户特点总结:

  1. 拥有以太余额。
  2. 有相关的可执行代码(合约代码)。
  3. 合约代码能够被交易或者其他合约消息调用。
  4. 合约代码被执行时可再调用其他合约代码。
  5. 合约代码被执行时可执行复杂运算,可永久地改变合约内部的数据存储。
  • 区块链学习的书籍
  • 区块链入门教程
  • IBM教程

参考自:

  1. [比特币白皮书]https://www.8btc.com/wiki/bitcoin-a-peer-to-peer-electronic-cash-system)
  2. 以太坊白皮书
  3. 超级账本白皮书
  4. 闪电网络白皮书

Solidity

简介

Solidity是什么

  • Solidity 是一门面向合约的、为实现智能合约而创建的高级编程语言。这门语言受到了 C++,Python 和 Javascript 语言的影响,设计的目的是能在以太坊虚拟机(EVM)上运行。
  • Solidity 是静态类型语言,支持继承、库和复杂的用户定义类型等特性。
  • 内含的类型除了常见编程语言中的标准类型,还包括 address等以太坊独有的类型,Solidity 源码文件通常以 .sol 作为扩展名
  • 目前尝试 Solidity 编程的推荐方式是使用 Remix。Remix是一个基于 Web 浏览器的 IDE,它可以让你编写 Solidity 智能合约,然后部署并运行该智能合约。

Solidity语言特性

Solidity的语法接近于JavaScript,是一种面向对象的语言。但作为一种真正意义上运行在网络上的去中心合约,它又有很多的不同:

  • 以太坊底层基于帐户,而不是 UTXO,所以增加了一个特殊的address 的数据类型用于定位用户和合约账户。
  • 语言内嵌框架支持支付。提供了 payable 等关键字,可以在语言层面直接支持支付。
  • 使用区块链进行数据存储。数据的每一个状态都可以永久存储,所以在使用时需要确定变量使用内存,还是区块链存储。
  • 运行环境是在去中心化的网络上,所以需要强调合约或函数执行的调用的方式。
  • 不同的异常机制。一旦出现异常,所有的执行都将会被回撤,这主要是为了保证合约执行的原子性,以避免中间状态出现的数据不一致。

Solidity源码和智能合约

Solidity 源代码要成为可以运行在以太坊上的智能合约需要经历如下的

步骤:

  1. 用 Solidity 编写的智能合约源代码需要先使用编译器编译为字节码(Bytecode),编译过程中会同时产生智能合约的二进制接口规范(Application Binary Interface,简称为ABI);
  2. 通过交易(Transaction)的方式将字节码部署到以太坊网络,每次成功部署都会产生一个新的智能合约账户;
  3. 使用 Javascript 编写的 DApp 通常通过 web3.js + ABI去调用智能合约中的函数来实现数据的读取和修改。

合约结构

  • 状态变量(State Variables)作为合约状态的一部分,值会永久保存在存储空间内。
  • 函数(Functions)合约中可执行的代码块。
  • 函数修饰器(Function Modifiers)在函数声明中,用来补充修饰函数的语义。
  • 事件(Events)非常方便的 EVM 日志工具接口。

Solidity编译器安装以及简单使用

Remix 是一个开源的 IDE (集成开发环境),是一个浏览器在线编辑器。作为 Solidity 智能合约开发环境,Solidity IDE Remix(在线浏览器编辑器)提供基本的编译、部署至本地或测试网络、执行合约等功能。

remix安装及使用

一、浏览器端配置:

在浏览器端有俩个选择,分别为英文版与中文版

  • Remix中文版地址:http://remix.hubwiz.com
  • Remix英文版地址(推荐):https://remix.ethereum.org/

区块链学习笔记

步骤:

1、浏览器输入 https://remix.ethereum.org/

2、左侧可以看到所有的文件,下面是remix控制台

区块链学习笔记

上图小图标从左到右依次为:

  • 创建新文件
  • 创建新文件夹
  • Github代码片段分享
  • 表示打开一个本地文件

控制台图片如下:

区块链学习笔记

  • 1 从左至右表示隐藏控制台、清除控制台输出、pending的交易数量
  • 2 表示监听所有交易
  • 3 表示搜索框
  • 4 表示输出区域
  • 5 表示使用JavaScript与以太坊交互的区域,可以使用Web3对象

3、点击文件样式图标输入我们的文件名即可(以.sol为后缀)

区块链学习笔记

4、安装必要的插件

点击插件管理器,页面中为这个图标

区块链学习笔记

  • 安装compiler

    搜索关键字compiler

区块链学习笔记

5、写一个简单的样例

pragma solidity ^0.4.0;contract SimpleStorage {    uint storedData;    function set(uint x) public {        storedData = x;    }    function get() public view returns (uint) {        return storedData;    }}

第一行表明源代码使用Solidity版本0.4.0写的,并且使用0.4.0以上版本运行也没问题(最高到0.5.0,但是不包含0.5.0)。这是为了确保合约不会在新的编译器版本中突然行为异常。关键字 pragma 的含义是,一般来说,pragmas(编译指令)是告知编译器如何处理源代码的指令的。

Solidity中合约的含义就是一组代码(它的 函数 )和数据(它的 状态 ),它们位于以太坊区块链的一个特定地址上。 代码行 uint storedData; 声明一个类型为uint (256位无符号整数) 的状态变量,叫做 storedData 。 可以认为它是数据库里的一个位置,可以通过调用管理数据库代码的函数进行查询和变更。对于以太坊来说,上述的合约就是拥有合约(owning contract)。在这种情况下,函数 setget 可以用来变更或取出变量的值。

要访问一个状态变量,并不需要像 this. 这样的前缀,虽然这是其他语言常见的做法。

该合约能完成的事情并不多(由于以太坊构建的基础架构的原因):它能允许任何人在合约中存储一个单独的数字,并且这个数字可以被世界上任何人访问,且没有可行的办法阻止你发布这个数字。当然,任何人都可以再次调用 set ,传入不同的值,覆盖你的数字,但是这个数字仍会被存储在区块链的历史记录中。

区块链学习笔记

点击compile test.sol,可以看到编译按钮,建议将Auto compile打钩(自动编译),之后会在编译图标上看到一个以绿色为背景的对勾。

编译组件说明:

  • Compiler可以选择Solidity的编译器版本
  • Language可以选择编程语言
  • EVM Version可以选择EVM虚拟机版本
  • Auto compile可以设置自动编译,修改完代码后自动执行编译操作
  • Enable optimization可以设置对编译进行优化
  • Hide warnings可以设置隐藏警告信息。
  • Contract选择需要编译的合约
  • Publish on SwarmPublish on Ipfs分别将合约上传到Swarm和Ipfs这两个分布式文件系统上去
  • Compilation Details很重要,可以查看编译的信息,包括ABI、字节码、函数Hash等
  • ABIBytecode分别复制ABI和字节码。
  • 再下面的部分空白用来显示编译的Warnings和Errors。

我们点击Compilation Details就能看到编译之后的一些信息,如下图所示(部分)

区块链学习笔记

  • NAME:合约名
  • METADATA:一些编译相关的信息,比如版本、所用的语言、设置等
  • BYTECODE:写入区块的字节码
  • ABI:此智能合约对应的 ABI ,也就是我们合约里面定义的一些接口
  • WEB3DEPLOY:智能合约编译之后的发布命令,这个就是比较重要的,之后的web3就是调用这段命令来部署合约的
  • METADATAHASH:数据的一个哈希值
  • SWARMLOCATION:Swarm网络的一个地址
  • FUNCTIONHASHES:合约定义的方法的hash,其实我们执行合约的时候就是通过这个hash去找到对应的方法进行执行的
  • GASESTIMATES:关于矿工费的一个预算,在ETH上进行合约的部署,执行等都是需要矿工费的。一般合约代码越多矿工费越高。

点击下面的run图标,可以看到部署,以及账户信息,环境等等

区块链学习笔记

点击deploy之后天可以看到自己的合约已经部署完成,打开之后可以看见我们写的函数set,get了,给set函数输入一个值,点击get会得到相应的值

区块链学习笔记

  • Environment 表示合约部署的环境。Javascript VM是虚拟了一个节点,而Injected Web3Web3 Provider则真正连接一个节点。
  • Account代表不同的虚拟账户,每个虚拟账户每个有 100 ETH
  • Deploy表示合约部署按钮
  • Deployed Contracts表示已经部署的合约

中文版界面与英文版界面有些许不一致,但都大同小异: Solidity语言编辑器REMIX指导大全

二、本地配置:

  • win下
  • ubuntu下

三、Docker

我们为编译器提供了最新的docker构建。 stable 仓库里的是已发布的版本,nightly 仓库则是在开发分支中的带有不稳定变更的版本。

docker run ethereum/solc:stable solc --version

目前,docker 镜像只含有 solc 的可执行程序,因此你需要额外的工作去把源代码和输出目录连接起来。

Solidity基础操作

教程Solifity中文文档、Solidity英文文档

Solidity源文件布局

源文件可以被版本杂注pragma所注解,表明要求的编译器版本

  • 例如:
pragma solidity ^0.4.0;

这样,源文件将既不允许低于 0.4.0 版本的编译器编译, 也不允许高于(包含) 0.5.0 版本的编译器编译(第二个条件因使用 ^ 被添加)。 这种做法的考虑是,编译器在 0.5.0 版本之前不会有重大变更,所以可确保源代码始终按预期被编译。 上面例子中不固定编译器的具体版本号,因此编译器的补丁版也可以使用。

import(导入其它源文件)

  • Solidity 所支持的导入语句import,语法同 JavaScript(从ES6 起)非常类似
import \"filename\";

从“filename”中导入所有的全局符号到当前全局作用域中

import * as symbolName from \"filename\";

创建一个新的全局符号 symbolName,其成员均来自 “filename”中全局符号

import {symbol1 as alias, symbol2} from \"filename\";

创建新的全局符号 alias 和 symbol2,分别从 “filename” 引用 symbol1 和 symbol2

import \"filename\" as symbolName;

这条语句等同于 import * as symbolName from “filename”;

注释

可以使用单行注释(//)和多行注释(/* */)

// 这是一个单行注释。/*这是一个多行注释。*/

数据类型与运算符

Solidity值类型介绍

  • 布尔(bool)

可能的取值为字符常量值 true 或 false

例子:

pragma solidity ^0.4.0;contract helloworld {    bool boola=true; //声明一个布尔类型的值,只用一个等号    function booltesta() public view returns(bool){        return boola;    }        function booltestb(int a,int b) public pure returns(bool){        return a==b;    }}

区块链学习笔记

  • 整型(int/uint)**:

int / uint :分别表示有符号和无符号的不同位数的整型变量。 支持关键字 uint8uint256 (无符号,从 8 位到 256 位)以及 int8int256,以 8 位为步长递增。 uintint 分别是 uint256int256 的别名。

  • 定长浮点型(fixed / ufixed)

fixed/ ufixed:表示各种大小的有符号和无符号的定长浮点型。 在关键字 ufixedMxNfixedMxN 中,M 表示该类型占用的位数N 表示可用的小数位数M必须能整除 8,即 8 到 256 位。 N则可以是从0 到 80 之间的任意数 ufixedfixed 分别是 ufixed128x19fixed128x19 的别名。

  • 地址(address 重点,后面细讲)

地址类型存储一个 20 字节的值(以太坊地址的大小)。 地址类型也有成员变量,并作为所有合约的基础。

地址类型成员变量:balancetransfer

可以使用 balance 属性来查询一个地址的余额, 也可以使用 transfer 函数向一个地址发送 以太币 (以 wei 为单位):

address x = 0x123;address myAddress = this;if (x.balance = 10) x.transfer(10);

注:如果 x 是一个合约地址,它的代码(更具体来说是它的 fallback 函数,如果有的话)会跟 transfer 函数调用一起执行(这是 EVM 的一个特性,无法阻止)。 如果在执行过程中用光了 gas 或者因为任何原因执行失败,以太币 交易会被打回,当前的合约也会在终止的同时抛出异常。

  • 定长字节数组

关键字有 bytes1, bytes2, bytes3, …, bytes32 .length 表示这个字节数组的长度(只读).

注:可以将 byte[] 当作字节数组使用,但这种方式非常浪费存储空间,准确来说,是在传入调用时,每个元素会浪费 31 字节。 更好地做法是使用 bytes

  • 变长字节数组

bytes:变长字节数组。它并不是值类型。

string:变长 UTF-8 编码字符串类型。并不是值类型。

  • 地址字面常数(Address Literals)

比如像 0xdCad3a6d3569DF655070DEd06cb7A1b2Ccd1D3AF 这样的通过了地址校验和测试的十六进制字面常数属于 address 类型。 长度在 39 到 41 个数字的,没有通过校验和测试而产生了一个警告的十六进制字面常数视为正常的有理数字面常数。

  • 有理数和整数字面常数

整数字面常数由范围在 0-9 的一串数字组成,表现成十进制。 例如,69 表示数字 69。 Solidity 中是没有八进制的,因此前置 0 是无效的。

十进制小数字面常数带有一个 .,至少在其一边会有一个数字。 比如:1.,.1,和 1.3

科学符号也是支持的,尽管指数必须是整数,但底数可以是小数。 比如:2e10, -2e10, 2e-10, 2.5e1

数值字面常数表达式本身支持任意精度,除非它们被转换成了非字面常数类型(也就是说,当它们出现在非字面常数表达式中时就会发生转换)。 这意味着在数值常量表达式中, 计算不会溢出而除法也不会截断。

例如, (2**800 + 1) - 2**800 的结果是字面常数 1 (属于 uint8 类型),尽管计算的中间结果已经超过了 以太坊虚拟机 的机器字长度。 此外, .5 * 8 的结果是整型 4 (尽管有非整型参与了计算)

  • 字符串字面常数

字符串字面常数是指由双引号或单引号引起来的字符串(\"foo\"或者 \'bar\')。 不像在 C 语言中那样带有结束符;\"foo\" 相当于 3 个字节而不是 4 个。 和整数字面常数一样,字符串字面常数的类型也可以发生改变,但它们可以隐式地转换成 bytes1,……,bytes32,如果合适的话,还可以转换成 bytes 以及 string

  • 十六进制字面常数

十六进制字面常数以关键字 hex 打头,后面紧跟着用单引号或双引号引起来的字符串(例如,hex\"001122FF\")。 字符串的内容必须是一个十六进制的字符串,它们的值将使用二进制表示。

  • 枚举(enum)

一种用户可以定义类型的方法,与C语言类似,默认从0开始递增,一般用来模拟合约的状态

pragma solidity ^0.4.16;contract test {    enum ActionChoices { GoLeft, GoRight, GoStraight, SitStill };    ActionChoices choice;    ActionChoices constant defaultChoice = ActionChoices.GoStraight;    function setGoStraight() public {        choice = ActionChoices.GoStraight;    }    // 由于枚举类型不属于 |ABI| 的一部分,因此对于所有来自 Solidity 外部的调用,    // \"getChoice\" 的签名会自动被改成 \"getChoice() returns (uint8)\"。    // 整数类型的大小已经足够存储所有枚举类型的值,随着值的个数增加,    // 可以逐渐使用 `uint16` 或更大的整数类型。    function getChoice() public view returns (ActionChoices) {        return choice;    }    function getDefaultChoice() public pure returns (uint) {        return uint(defaultChoice);    }}
  • 函数(function)

函数类型是一种表示函数的类型。可以将一个函数赋值给另一个函数类型的变量,也可以将一个函数作为参数进行传递,还能在函数调用中返回函数类型变量。 函数类型有两类:- 内部(internal) 函数和 外部(external) 函数:

内部函数只能在当前合约内被调用(更具体来说,在当前代码块内,包括内部库函数和继承的函数中),因为它们不能在当前合约上下文的外部被执行。 调用一个内部函数是通过跳转到它的入口标签来实现的,就像在当前合约的内部调用一个函数。

外部函数由一个地址和一个函数签名组成,可以通过外部函数调用传递或者返回。

函数类型表示成如下的形式

区块链学习笔记

function () {internal|external} [pure|constant|view|payable] [returns ()]

与参数类型相反,返回类型不能为空 —— 如果函数类型不需要返回,则需要删除整个 returns () 部分。

函数类型默认是内部函数,因此不需要声明 internal 关键字。 与此相反的是,合约中的函数本身默认是 public的,只有当它被当做类型名称时,默认才是内部函数。

有两种方法可以访问当前合约中的函数:一种是直接使用它的名字,f ,另一种是使用 this.f 。 前者适用于内部函数,后者适用于外部函数。

如果当函数类型的变量还没有初始化时就调用它的话会引发一个异常。 如果在一个函数被 delete 之后调用它也会发生相同的情况。

如果外部函数类型在 Solidity 的上下文环境以外的地方使用,它们会被视为 function 类型。 该类型将函数地址紧跟其函数标识一起编码为一个 bytes24 类型。

请注意,当前合约的 public 函数既可以被当作内部函数也可以被当作外部函数使用。 如果想将一个函数当作内部函数使用,就用 f 调用,如果想将其当作外部函数,使用 this.f

Solidity函数可见性

函数的可见性可以指定为 external,public ,internal 或者 private;对于状态变量,不能设置为 external ,默认是 internal。

  • external :外部函数作为合约接口的一部分,意味着我们可以从其他合约和交易中调用。 一个外部函数 f 不能从内部调用(即 f 不起作用,但 this.f ( ) 可以)。 当收到大量数据的时候,外部函数有时候会更有效率。
  • public :public 函数是合约接口的一部分,可以在内部或通过消息调用。对于 public 状态变量, 会自动生成一个 getter 函数。
  • internal :这些函数和状态变量只能是内部访问(即从当前合约内部或从它派生的合约访问),不使用 this 调用。
  • private :private 函数和状态变量仅在当前定义它们的合约中使用,并且不能被派生合约使用。

Solidity函数状态可变性

  • pure:纯函数,不允许修改或访问状态
  • view:不允许修改状态
  • payable:允许从消息调用中接收以太币Ether 。
  • constant:与view相同,一般只修饰状态变量,不允许赋值(除初始化以外)

内部函数调用

当前合约中的函数可以直接(“从内部”)调用,也可以递归调用,就像下边这个荒谬的例子一样

pragma solidity ^0.4.16;contract C {    function g(uint a) public pure returns (uint ret) { return f(); }    function f() internal pure returns (uint ret) { return g(7) + f(); }}

这些函数调用在 EVM 中被解释为简单的跳转。这样做的效果就是当前内存不会被清除,也就是说,通过内部调用在函数之间传递内存引用是非常有效的。

外部函数调用

表达式 this.g(8); 和 c.g(2); (其中 c 是合约实例)也是有效的函数调用,但是这种情况下,函数将会通过一个消息调用来被“外部调用”,而不是直接的跳转。 请注意,不可以在构造函数中通过 this 来调用函数,因为此时真实的合约实例还没有被创建。

如果想要调用其他合约的函数,需要外部调用。对于一个外部调用,所有的函数参数都需要被复制到内存。

当调用其他合约的函数时,随函数调用发送的 Wei 和 gas 的数量可以分别由特定选项 .value().gas() 指定:

pragma solidity ^0.4.0;contract InfoFeed {    function info() public payable returns (uint ret) { return 42; }}contract Consumer {    InfoFeed feed;    function setFeed(address addr) public { feed = InfoFeed(addr); }    function callFeed() public { feed.info.value(10).gas(800)(); }}

payable 修饰符要用于修饰 info,否则,.value() 选项将不可用。

注意,表达式 InfoFeed(addr) 进行了一个的显式类型转换,说明”我们知道给定地址的合约类型是 InfoFeed “并且这不会执行构造函数。 显式类型转换需要谨慎处理。绝对不要在一个你不清楚类型的合约上执行函数调用。

我们也可以直接使用 function setFeed(InfoFeed _feed) { feed = _feed; } 。 注意一个事实,feed.info.value(10).gas(800) 只(局部地)设置了与函数调用一起发送的 Wei 值和 gas 的数量,只有最后的圆括号执行了真正的调用。

如果被调函数所在合约不存在(也就是账户中不包含代码)或者被调用合约本身抛出异常或者 gas 用完等,函数调用会抛出异常。

引用类型介绍

比起之前讨论过的值类型,在处理复杂的类型(即占用的空间超过 256 位的类型)时,我们需要更加谨慎。 由于拷贝这些类型变量的开销相当大,我们不得不考虑它的存储位置,是将它们保存在 内存 (并不是永久存储)中, 还是 存储 (保存状态变量的地方)中。

  • 数据位置

所有的复杂类型,即 数组结构 类型,都有一个额外属性,“数据位置”,说明数据是保存在 内存 中还是 存储 中。 根据上下文不同,大多数时候数据有默认的位置,但也可以通过在类型名后增加关键字 storagememory 进行修改。 函数参数(包括返回的参数)的数据位置默认是 memory, 局部变量的数据位置默认是 storage,状态变量的数据位置强制是 storage

也存在第三种数据位置, calldata ,这是一块只读的,且不会永久存储的位置,用来存储函数参数。 外部函数的参数(非返回参数)的数据位置被强制指定为 calldata,效果跟 memory 差不多。

例子:

pragma solidity ^0.4.0;contract C {    uint[] x; // x 的数据存储位置是 storage    // memoryArray 的数据存储位置是 memory    function f(uint[] memoryArray) public {        x = memoryArray; // 将整个数组拷贝到 storage 中,可行        var y = x;  // 分配一个指针(其中 y 的数据存储位置是 storage),可行        y[7]; // 返回第 8 个元素,可行        y.length = 2; // 通过 y 修改 x,可行        delete x; // 清除数组,同时修改 y,可行        // 下面的就不可行了;需要在 storage 中创建新的未命名的临时数组, /        // 但 storage 是“静态”分配的:        // y = memoryArray;        // 下面这一行也不可行,因为这会“重置”指针,        // 但并没有可以让它指向的合适的存储位置。        // delete y;        g(x); // 调用 g 函数,同时移交对 x 的引用        h(x); // 调用 h 函数,同时在 memory 中创建一个独立的临时拷贝    }    function g(uint[] storage storageArray) internal {}    function h(uint[] memoryArray) public {}}

归纳:

强制指定的数据位置:

  1. 外部函数的参数(不包括返回参数): calldata
  2. 状态变量: storage

默认数据位置:

  1. 函数参数(包括返回参数): memory
  2. 所有其它局部变量: storage
  • 数组

数组可以在声明时指定长度,也可以动态调整大小。 对于 存储 的数组来说,元素类型可以是任意的(即元素也可以是数组类型,映射类型或者结构体)。 对于 内存 的数组来说,元素类型不能是映射类型,如果作为 public 函数的参数,它只能是 ABI 类型。

一个元素类型为 T,固定长度为 k 的数组可以声明为 T[k],而动态数组声明为 T[]

举个例子,一个长度为 5,元素类型为 uint 的动态数组的数组,应声明为 uint[][5] (注意这里跟其它语言比,数组长度的声明位置是反的)。 要访问第三个动态数组的第二个元素,你应该使用 x[2][1](数组下标是从 0 开始的,且访问数组时的下标顺序与声明时相反,也就是说,x[2] 是从右边减少了一级)。。

bytesstring 类型的变量是特殊的数组。 bytes 类似于 byte[],但它在 calldata 中会被“紧打包”(译者注:将元素连续地存在一起,不会按每 32 字节一单元的方式来存放)。 stringbytes 相同,但(暂时)不允许用长度或索引来访问。

注: 如果想要访问以字节表示的字符串 s,请使用 bytes(s).length / bytes(s)[7] = \'x\';。 注意这时你访问的是 UTF-8 形式的低级bytes 类型,而不是单个的字符。

成员

length:

数组有 length 成员变量表示当前数组的长度。 动态数组可以在 存储 (而不是 内存 )中通过改变成员变量 .length 改变数组大小。 并不能通过访问超出当前数组长度的方式实现自动扩展数组的长度。 一经创建,内存 数组的大小就是固定的(但却是动态的,也就是说,它依赖于运行时的参数)。 push: 变长的 存储 数组以及 bytes 类型(而不是 string 类型)都有一个叫做 push 的成员函数,它用来附加新的元素到数组末尾。 这个函数将返回新的数组长度。

例子:

pragma solidity ^0.4.16;contract ArrayContract {    uint[2**20] m_aLotOfIntegers;    // 注意下面的代码并不是一对动态数组,    // 而是一个数组元素为一对变量的动态数组(也就是数组元素为长度为 2 的定长数组的动态数组)。    bool[2][] m_pairsOfFlags;    // newPairs 存储在 memory 中 —— 函数参数默认的存储位置    function setAllFlagPairs(bool[2][] newPairs) public {        // 向一个 storage 的数组赋值会替代整个数组        m_pairsOfFlags = newPairs;    }    function setFlagPair(uint index, bool flagA, bool flagB) public {        // 访问一个不存在的数组下标会引发一个异常        m_pairsOfFlags[index][0] = flagA;        m_pairsOfFlags[index][1] = flagB;    }    function changeFlagArraySize(uint newSize) public {        // 如果 newSize 更小,那么超出的元素会被清除        m_pairsOfFlags.length = newSize;    }    function clear() public {        // 这些代码会将数组全部清空        delete m_pairsOfFlags;        delete m_aLotOfIntegers;        // 这里也是实现同样的功能        m_pairsOfFlags.length = 0;    }    bytes m_byteData;    function byteArrays(bytes data) public {        // 字节的数组(语言意义中的 byte 的复数 ``bytes``)不一样,因为它们不是填充式存储的,        // 但可以当作和 \"uint8[]\" 一样对待        m_byteData = data;        m_byteData.length += 7;        m_byteData[3] = byte(8);        delete m_byteData[2];    }    function addFlag(bool[2] flag) public returns (uint) {        return m_pairsOfFlags.push(flag);    }    function createMemoryArray(uint size) public pure returns (bytes) {        // 使用 `new` 创建动态 memory 数组:        uint[2][] memory arrayOfPairs = new uint[2][](size);        // 创建一个动态字节数组:        bytes memory b = new bytes(200);        for (uint i = 0; i < b.length; i++)            b[i] = byte(i);        return b;    }}
  • 结构体

Solidity 支持通过构造结构体的形式定义新的类型,以下是一个结构体的示例:

struct Funder {    address addr;    uint amount;}struct Campaign {    address beneficiary;    uint fundingGoal;    uint numFunders;    uint amount;    mapping (uint => Funder) funders;}
  • 映射 映射类型在声明时的形式为 mapping(_KeyType => _ValueType)。 其中 _KeyType 可以是除了映射、变长数组、合约、枚举以及结构体以外的几乎所有类型。 _ValueType 可以是包括映射类型在内的任何类型。

映射可以视作 哈希表 https://en.wikipedia.org/wiki/Hash_table,它们在实际的初始化过程中创建每个可能的 key, 并将其映射到字节形式全是零的值:一个类型的 默认值。然而下面是映射与哈希表不同的地方: 在映射中,实际上并不存储 key,而是存储它的 keccak256 哈希值,从而便于查询实际的值。

正因为如此,映射是没有长度的,也没有 key 的集合或 value 的集合的概念。

只有状态变量(或者在 internal 函数中的对于存储变量的引用)可以使用映射类型。。

可以将映射声明为 public,然后来让 Solidity 创建一个 getter。_KeyType 将成为 getter 的必须参数,并且 getter 会返回 _ValueType

_ValueType 也可以是一个映射。这时在使用 getter 时将将需要递归地传入每个 _KeyType参数。

pragma solidity ^0.4.0;contract MappingExample {    mapping(address => uint) public balances;    function update(uint newBalance) public {        balances[msg.sender] = newBalance;    }}contract MappingUser {    function f() public returns (uint) {        MappingExample m = new MappingExample();        m.update(100);        return m.balances(this);    }}

涉及LValues 的运算符

  • 删除

delete a 的结果是将 a 的类型在初始化时的值赋值给 a。即对于整型变量来说,相当于 a = 0, 但 delete 也适用于数组,对于动态数组来说,是将数组的长度设为 0,而对于静态数组来说,是将数组中的所有元素重置。 如果对象是结构体,则将结构体中的所有属性重置。

delete 对整个映射是无效的(因为映射的键可以是任意的,通常也是未知的)。 因此在你删除一个结构体时,结果将重置所有的非映射属性,这个过程是递归进行的,除非它们是映射。 然而,单个的键及其映射的值是可以被删除的。

理解 delete a的效果就像是给 a 赋值很重要,换句话说,这相当于在 a中存储了一个新的对象。

pragma solidity ^0.4.0;contract DeleteExample {    uint data;    uint[] dataArray;    function f() public {        uint x = data;        delete x; // 将 x 设为 0,并不影响数据        delete data; // 将 data 设为 0,并不影响 x,因为它仍然有个副本        uint[] storage y = dataArray;        delete dataArray;        // 将 dataArray.length 设为 0,但由于 uint[] 是一个复杂的对象,y 也将受到影响,        // 因为它是一个存储位置是 storage 的对象的别名。        // 另一方面:\"delete y\" 是非法的,引用了 storage 对象的局部变量只能由已有的 storage 对象赋值。    }}

单位和全局变量

以太币单位

以太币 单位之间的换算就是在数字后边加上 weifinneyszaboether 来实现的,如果后面没有单位,缺省为 Wei。例如 2 ether == 2000 finney 的逻辑判断值为 true

时间单位

秒是缺省时间单位,在时间单位之间,数字后面带有 secondsminuteshoursdaysweeksyears 的可以进行换算,基本换算关系与现实生活相符。

特殊变量和函数

在全局命名空间中已经存在了(预设了)一些特殊的变量和函数,他们主要用来提供关于区块链的信息或一些通用的工具函数。

区块和交易属性

  • block.blockhash(uint blockNumber) returns (bytes32):指定区块的区块哈希——仅可用于最新的 256 个区块且不包括当前区块;而 blocks 从 0.4.22 版本开始已经不推荐使用,由 blockhash(uint blockNumber) 代替
  • block.coinbase (address): 挖出当前区块的矿工地
  • block.difficulty (uint): 当前区块难度
  • block.gaslimit (uint): 当前区块 gas 限额
  • block.number (uint): 当前区块号
  • block.timestamp (uint): 自 unix epoch 起始当前区块以秒计的时间戳
  • gasleft() returns (uint256):剩余的 gas
  • msg.data (bytes): 完整的 calldata
  • msg.gas (uint): 剩余 gas – 自 0.4.21 版本开始已经不推荐使用,由 gesleft() 代替
  • msg.sender (address): 消息发送者(当前调用)
  • msg.sig (bytes4): calldata 的前 4 字节(也就是函数标识符)
  • msg.value (uint): 随消息发送的 wei 的数量
  • now (uint): 目前区块时间戳(block.timestamp
  • tx.gasprice (uint): 交易的gas 价格
  • tx.origin (address): 交易发起者(完全的调用链)

ABI 编码函数

  • abi.encode(...) returns (bytes): ABI – 对给定参数进行编码
  • abi.encodePacked(...) returns (bytes):对给定参数执行 紧打包编码
  • abi.encodeWithSelector(bytes4 selector, ...) returns (bytes): ABI – 对给定参数进行编码,并以给定的函数选择器作为起始的 4 字节数据一起返回
  • abi.encodeWithSignature(string signature, ...) returns (bytes):等价于 abi.encodeWithSelector(bytes4(keccak256(signature), ...)

错误处理

  • assert(bool condition): 如果条件不满足,则使当前交易没有效果 — 用于检查内部错误。
  • require(bool condition): 如果条件不满足则撤销状态更改 – 用于检查由输入或者外部组件引起的错误。
  • require(bool condition, string message): 如果条件不满足则撤销状态更改 – 用于检查由输入或者外部组件引起的错误,可以同时提供一个错误消息。
  • revert(): 终止运行并撤销状态更改。
  • revert(string reason): 终止运行并撤销状态更改,可以同时提供一个解释性的字符串。

地址相关


  • .balance (uint256)
    : 以 Wei 为单位的 地址类型 的余额。

  • .transfer(uint256 amount)
    : 向 地址类型 发送数量为 amount 的 Wei,失败时抛出异常,发送 2300 gas 的矿工费,不可调节。

  • .send(uint256 amount) returns (bool)
    : 向 地址类型 发送数量为 amount 的 Wei,失败时返回 false,发送 2300 gas 的矿工费用,不可调节。

  • .call(...) returns (bool)
    : 发出低级函数 CALL,失败时返回 false,发送所有可用 gas,可调节。

  • .callcode(...) returns (bool)
    : 发出低级函数 CALLCODE,失败时返回 false,发送所有可用 gas,可调节。

  • .delegatecall(...) returns (bool):
    发出低级函数 DELEGATECALL,失败时返回 false,发送所有可用 gas,可调节。

表达式和控制结构(*)

控制结构

avaScript 中的大部分控制结构在 Solidity 中都是可用的,除了 switchgoto。 因此 Solidity 中有 if,else,while,do,for,break,continue,return,? :这些与在 C 或者 JavaScript 中表达相同语义的关键词。

用于表示条件的括号 不可以 被省略,单语句体两边的花括号可以被省略。

注意,与 C 和 JavaScript 不同, Solidity 中非布尔类型数值不能转换为布尔类型,因此 if (1) { ... } 的写法在 Solidity 中 无效 。

当一个函数有多个输出参数时, return (v0, v1, ...,vn) 写法可以返回多个值。不过元素的个数必须与输出参数的个数相同

通过 new 创建合约

使用关键字 new 可以创建一个新合约。待创建合约的完整代码必须事先知道,因此递归的创建依赖是不可能的。

pragma solidity ^0.4.0;contract D {    uint x;    function D(uint a) public payable {        x = a;    }}contract C {    D d = new D(4); // 将作为合约 C 构造函数的一部分执行    function createD(uint arg) public {        D newD = new D(arg);    }    function createAndEndowD(uint arg, uint amount) public payable {        //随合约的创建发送 ether        D newD = (new D).value(amount)(arg);    }}

如示例中所示,使用 .value() 选项创建 D 的实例时可以转发 Ether,但是不可能限制 gas 的数量。如果创建失败(可能因为栈溢出,或没有足够的余额或其他问题),会引发异常。

错误处理:Assert, Require, Revert and Exceptions

Solidity 使用状态恢复异常来处理错误。这种异常将撤消对当前调用(及其所有子调用)中的状态所做的所有更改,并且还向调用者标记错误。 便利函数 assertrequire 可用于检查条件并在条件不满足时抛出异常。assert 函数只能用于测试内部错误,并检查非变量。

require 函数用于确认条件有效性,例如输入变量,或合约状态变量是否满足条件,或验证外部合约调用返回的值。 如果使用得当,分析工具可以评估你的合约,并标示出那些会使 assert 失败的条件和函数调用。 正常工作的代码不会导致一个 assert语句的失败;如果这发生了,那就说明出现了一个需要你修复的 bug。

还有另外两种触发异常的方法:revert 函数可以用来标记错误并恢复当前的调用。 revert 调用中包含有关错误的详细信息是可能的,这个消息会被返回给调用者。已经不推荐的关键字 throw 也可以用来替代 revert() (但无法返回错误消息)。

在下例中,你可以看到如何轻松使用require检查输入条件以及如何使用assert检查内部错误,注意,你可以给 require 提供一个消息字符串,而 assert 不行。

pragma solidity ^0.4.22;contract Sharer {    function sendHalf(address addr) public payable returns (uint balance) {        require(msg.value % 2 == 0, \"Even value required.\");        uint balanceBeforeTransfer = this.balance;        addr.transfer(msg.value / 2);                    //由于转移函数在失败时抛出异常并且不能在这里回调,因此我们应该没有办法仍然有一半的钱。        assert(this.balance == balanceBeforeTransfer - msg.value / 2);        return this.balance;    }}

合约

Solidity 合约类似于面向对象语言中的类。合约中有用于数据持久化的状态变量,和可以修改状态变量的函数。 调用另一个合约实例的函数时,会执行一个 EVM 函数调用,这个操作会切换执行时的上下文,这样,前一个合约的状态变量就不能访问了。

创建合约

可以通过以太坊交易“从外部”或从 Solidity 合约内部创建合约。 创建合约时,会执行一次构造函数(与合约同名的函数)。构造函数是可选的。只允许有一个构造函数,这意味着不支持重载。

在内部,构造函数参数在合约代码之后通过 ABI 编码 传递,但是如果你使用 web3.js 则不必关心这个问题。

如果一个合约想要创建另一个合约,那么创建者必须知晓被创建合约的源代码(和二进制代码)。 这意味着不可能循环创建依赖项。

getter 函数

编译器自动为所有 public 状态变量创建 getter 函数。对于下面给出的合约,编译器会生成一个名为 data 的函数, 该函数不会接收任何参数并返回一个 uint ,即状态变量 data 的值。可以在声明时完成状态变量的初始化

pragma solidity ^0.4.0;contract C {    uint public data = 42;}contract Caller {    C c = new C();    function f() public {        uint local = c.data();    }}

getter 函数具有外部可见性。如果在内部访问 getter(即没有 this. ),它被认为一个状态变量。 如果它是外部访问的(即用 this. ),它被认为为一个函数。

View 函数

可以将函数声明为 view 类型,这种情况下要保证不修改状态。

下面的语句被认为是修改状态:

  1. 修改状态变量。
  2. 产生事件。
  3. 创建其它合约。
  4. 使用 selfdestruct。
  5. 通过调用发送以太币。
  6. 调用任何没有标记为 view 或者 pure 的函数。
  7. 使用低级调用。
  8. 使用包含特定操作码的内联汇编。
pragma solidity ^0.4.16;contract C {    function f(uint a, uint b) public view returns (uint) {        return a * (b + 42) + now;    }}

Pure 函数

函数可以声明为 pure ,在这种情况下,承诺不读取或修改状态。

除了上面解释的状态修改语句列表之外,以下被认为是从状态中读取:

  1. 读取状态变量。
  2. 访问 this.balance 或者 .balance。
  3. 访问 block,tx, msg 中任意成员 (除 msg.sig 和 msg.data 之外)。
  4. 调用任何未标记为 pure 的函数。
  5. 使用包含某些操作码的内联汇编。
pragma solidity ^0.4.16;contract C {    function f(uint a, uint b) public pure returns (uint) {        return a * (b + 42);    }}

Hyperledger fabric

非常nice的一个教程网址:

https://hyperledger-fabric.readthedocs.io/zh_CN/release-2.2/blockchain.html

一个更nice(文龙推荐的)网址:

https://blog.51cto.com/u_9291927/2304828

Linux 基金会于2015年创建了 Hyperledger(超级账本)项目,以推进跨行业的区块链技术。它不是用来宣布一个区块链标准,而是鼓励通过社区流程开发区块链技术的协作方法,其中包括鼓励开放式开发、和随着时间的推移采用关键标准的知识产权。

Hyperledger Fabric 是 Hyperledger 中的区块链项目之一。与其他区块链技术一样,它有一个账本,使用智能合约,是一个参与者管理交易的系统。

Hyperledger Fabric 与其他区块链系统不同的地方是 私有许可 。与允许未知身份参与网络的开放式非许可系统(需要诸如“工作量证明”之类的协议来验证交易并保护网络)不同,Hyperledger Fabric 网络的成员需要从可信赖的 成员服务提供者(MSP) 注册。

Hyperledger Fabric 还提供创建 通道 的功能,允许一组参与者创建各自的交易账本。对于某些网络而言,这是一个特别重要的选择。这些网络中,一些参与者可能是竞争对手,并且不希望他们做出的每笔交易都被每个参与者知晓,例如,他们只向某些参与者提供的特殊价格,而其他人不是。如果两个参与者组成一个通道,那么只有这两个参与者拥有该通道的账本副本,而其他参与者没有。

Hyperledger Fabric 是分布式账本解决方案的平台,采用模块化架构,提供高安全性、弹性、灵活性和可扩展性。它被设计为支持以可插拔方式实现不同组件,并适应复杂的经济生态系统。其关键组件包括:

  1. 客户端( Client) : 封装了区块链网络的底层接口,可以 通过命令行或 Fabric SDK 调用,用于在应用和区块链网络之 间进行交互。客户端能够实现在网络中发起交易( transaction) 、监听消息、更新配置、启停节点等功能。

  2. 节点( Peer) : 包括背书节点 ( Endorser) 和确认节点 ( Committer) 两类。背书节点对收到的请求按事先制定的策略 ( Policy) 进行检查( 例如,必须有属于组织 A 和组织 B 的背书节点同时批准交易的合法性) ,计算交易执行结果,如果符合 要求则予以签名并返回。确认节点负责向区块写入交易,更新账本的本地副本。节点通常都具有确认功能,一部分节点具有背书功能。

  3. 排序服务( Ordering Service) : 为收集到的合法交易按 一定的时间顺序进行排序,再打包成区块数据广播至区块链网络。排序服务所采用的共识机制是可插拔的,其去中心化程 度可以自行选择。

  4. MSP( Membership Service Provider,成员服务提供者) : 区块链网络中负责成员身份管理和认证的抽象组件. Hyperledger Fabric 中的成员通常从属于某个组织 ( Organization) ,多个组织最终结成了联盟。而为了管理组织之间的关系及其成员的权限,MSP 定义了一系列颁发和校验数字证书 的标准化规范,在节点、排序服务、通道等组件的配置文件中均包含被授权组织的 MSP 相关信息。 Fabric CA 是官方基于 PKI 的 MSP 默认实现。

  5. 链码( Chaincode) : 在其他区块链平台上也称作“智能 合约”。 Hyperledger Fabric 中提供了系统链码和用户链码,前 者用于系统内部的管理和维护,后者用于提供对外部应用的可编程支持,通过执行代码逻辑与账本交互。用户链码可采用 Golang、Java、Node.js 等通用编程语言编写,在节点的 Docker 容器环境中隔离运行。

  6. 通道( Channel) : 可以认为是建立在区块链网络上的子网,能隔离交易,使得通道外部成员无法访问和修改通道内部的数据,实现区块链数据的权限管理。每个通道都有自己的访问策略、组织身份及排序服务等。

Hyperledger Fabric(超级账本)是一个基于私有链的区块链应用快速开发框架,是Hyperledger 体系架构中的众多项目之一。 该框架被用作开发基于区块链的应用程序、网络等的基础,通常简写为 Fabric,一笔交易的完成要经过以下几个流程,如图所示。

区块链学习笔记

Fabric 设计用于创建私有区块链,这些区块链可在链接到其他区块链实现的单个组织或联合组织中使用。 Fabric 有如下几个关键功能:

隐私(Privacy):Fabric 必须能够识别网络中的所有计算机节点,Fabric 网络中的准入成员必须通过成员资格服务提供商(MSP)加入并标识自己身份, 这就是所谓的“许可”成员资格。维护数据隐私对于许多行业而言至关重要,仅在这方面就使 Fabric 成为具有吸引力的架构选择。 重要的是要注意,Fabric 并不需要区块链的所有部分都得到许可,权限的必要性由设计网络的人自行决定。
通道(Channel):Fabric 将分类的账本划分为“通道”的功能,网络的成员可以在其中创建对大型网络不可见的独立交易集,这允许将更加敏感的数据信息与不需要访问它的节点隔离。
可扩展性(Scalability):Fabric 对大型企业的另一个吸引人的特征是 Fabric提供非常容易地可扩展性的网络,参与网络的节点数量可以快速扩展。 但是平台仍能够使用较少的资源集来处理大量数据,可以使用少量节点创建区块链,并按需扩展。
模块化(Modularity): Fabric 的体系结构设计成允许在不同的时间添加和实现单独的组件。 许多组件是可选的,可以完全省略或以后有需要是再引入,而不会影响平台的功能。 此功能旨在使公司能够自主选择实现什么和不需要实现什么,被认为是模块化的,一些组件包括达成共识的方法、身份识别的成员服务,分类账本存储本身,特定的访问 API 以及链码集成。
Hyperledger Fabric 框架可以与 Hyperledger 项目(例如 Burrow 和 Sawtooth)进行互相兼容性工作,以提供可扩展的数据平台。 在 Hyperledger 框架下的其他生态平台成员(例如 Composer,Quilt 和 Explorer)能够使用 Fabric 网络中的数据。

hyperledger CA

Hyperledger Fabric CA(Fabric 证书颁发机构)充任 Hyperledger Fabric 的成员准入资格的把关者。它处理成员的注册、证书和节点的监管。证书颁发机构在使 Fabric 成为许可的区块链、注册成员、跟踪网络中的身份以及移除弃用帐户方面起着核心作用。
Hyperledger Fabric CA 服务器采用 REST API 与 Fabric 网络的组件进行通讯,而 REST API 又与客户端应用程序设计所用的 Fabric SDK 或 Fabric CA 客户端的特殊实例进行交互。

智能合约

当智能合约被安装在 Peer 节点并且在通道上定义之后,它就可以被客户端应用调用了,这会由 Peer 节点返回给客户端应用。

这些交易的响应会和交易的提案打包到一起形成一个完整的经过背书的交易,他们会被分发到整个网络。我们会在之后更详细的了解,现在理解应用是如何调用智能合约来生成经过背书的交易就已经足够了。

智能合约是应用程序开发的重点,正如我们所看到的,一个链码中可定义一个或多个智能合约。将链码部署到网络中以后,网络上的组织就都可以使用该链码中的所有智能合约。这意味着只有管理员才需要考虑链码;其他人都只用考虑智能合约。

基于区块链的联邦学习系统

一个写了很多区块链和联邦学习结合的笔记的博主:

https://blog.csdn.net/aibiabcheng/category_10380751.html

全网最全开源工业缺陷数据集汇总:

https://zhuanlan.zhihu.com/p/195699093

公开数据集网址:

https://gas.graviti.cn/open-datasets?_ga=2.62493612.1453698399.1632962448-1970684789.1632962448

基于区块链的工业物联网联邦学习系统架构

于秋雨, 卢清华, 张卫山 (中国石油大学 (华东) 计算机科学与技术学院, 青岛 266580) 通讯作者: 卢清华, E-mail: dr.qinghua.lu@gmail.com

本文贡献

(1) 提出一个系统架构, 展示了不同部件间的交互, 为开发基于区块链的工业物联网联邦学习系统提供指导. 架构包括以下设计决策: 模型训练、客户数据存储、客户激励机制以及区块链部署.

(2) 提出区块链锚定协议, 确保可验证数据的完整性. 协议规定, 每隔一段时间, 使用客户端边缘设备收集到的数据创建默克尔树 (一个叶子节点代表一条客户数据), 并将根节点上传到区块链.

(3) 提出激励机制, 通过激励智能合约, 来鼓励客户贡献数据和计算资源参与模型训练, 用户会根据自己在本地训练模型的数据大小, 收到相应的代币奖励.

(4) 在真实的工业场景 (轴承故障检测) 中, 对系统架构可行性, 模型精度和性能进行了评估.

系统架构

对基于区块链的工业物联网联邦学习系统, 制定了一系列的功能需求和非功能需求. 其中功能需求包括:

(1) 在本地服务器进行模型训练;

(2) 在不上传本地数据的情况下, 基于本地模型参数生成全局模型;

(3) 融合得到的全局模型可用于分类;

(4) 根据客户在模型训练过程中的贡献进行奖励.

已确定的非功能需求包括:

(1) 保护边缘数据隐私;

(2) 具有良好的模型精度;

(3) 确保客户端数据的完整性;

(4) 维护区块链基础设施的可用性.

区块链学习笔记

实验分析

实验将系统架构部署在 6 台阿里巴巴云服务器 (2 VCPU, 8 GB RAM) 上, 其中 1 台云服务器作为中心服务器, 5 台云服务器作为客户端服务器.

  1. 区块链上的写入延迟比传统数据库中要长得多, 因为传播交易/块和各节点达成一致需要时间. 由于区块链用于审计和实现激励机制, 因此在本工作中不考虑区块链的写入延迟.
  2. 联邦学习模型可以取得和集中式学习模型相同的的精度.
  3. 集中式学习的通信开销要比联邦学习大得多, 当数据集非常大时, 采用联邦学习可以显著降低通信开销.

展望

在本文中, 大部分联邦学习任务是在客户端服务器上完成的. 在接下的研究工作中, 我们计划将所有训练任务从客户端服务器移到具有更强大计算和存储能力的客户端设备上. 此外, 我们计划进一步探讨如何提高客户端设备在模型融合过程中的可信度. 再者, 我们 计划在未来的研究中将激励机制与更多的因素关联.

基于区块链的工业互联网企业协同架构

曹玉红,荆博 (中国电子学会,北京 100036)

联邦学习

联邦学习有两种模式。一种是参数服务器模式,其中参数服务器将模型下发到各个节点,各个节点在本地进行模型的训练, 训练后产生的模型更新提交到参数服务器,参数服务器完成参数的聚合后再次将模型下发到点,迭代直到模型收敛。另一种是去中心化的模式,各个节点都可以充当参数服务器完成参数聚合,由具体算法决定将每一轮参数聚合的任务分配到哪个节点。

而区块链在其中可以记录每个企业更新的贡献程度,可以对更新溯源,从而防止恶意攻击,而且企业的贡献程度也可以作为企业的信用记录,用于企业挑选联邦学习合作方。如图展示了参数服务器模式下联邦学习 +区块链的运作模式,在参数服务器完成全局模型的更新后,区块链记录各方的更新和贡献。在去中心化模式下,记录更新和贡献的任务可以由完成参数聚合的节点承担。

区块链学习笔记

企业的账务数据上传到联盟链后,企业之间发生交易或者监管部门对企业账务存在疑问时,可以根据联盟链内相似企业数据进行对比,比如如果设 备型号相同,而输入产出比却相差很多,这其中就 可能存在异常。如图所示,监管部门也可以将人 工智能技术应用到账务审计,进行自动账务异常监测,智能筛选出可疑账务名单。由于人工智能的可解释性较弱,因此之后可以配合人工审查,对可疑企业的数据进行比对,进行更细粒度的审查。

区块链学习笔记

面临的挑战

虽然区块链技术的特点能很好地弥补工业互联网发展过程中存在的不足,但是二者结合仍然 面临着诸多挑战,可以总结为以下四个方面。

  1. 跨链交易:目前各类区块链应用都伴随着相应一条区块链的出现,各条区块链本身形成了区块链孤岛。 如何打通这些区块链,实现信息互通以及跨链交易的原子性,是未来区块链发展的关键。
  2. 安全和隐私:区块链作为一项新兴技术,依然面临着一些安全和隐私的威胁,比如路由劫持攻击、智能合约漏洞攻击、DDoS攻击、成员推断攻击等。这些威胁是整个区块链生态的不稳定因素所在。
  3. 可扩展性:随着更多的应用接入区块链,区块链本身的处理能力、存储能力、传输能力也会成为制约其发展的瓶颈。如果这一问题不能很好解决,区块链应用难以迈向工业级水平。
  4. 监管挑战:前三项挑战都是从技术的角度出发,但该应用模式更大的挑战在于针对区块链技术的法律监管。尤其是在区块链和工业互联网的结合模式 下,如何对内部执行的法律效力给予认定,如何界定其中的违法行为,如何管控联盟链内部运行活动等问题,都需要主管部门制定详细明确的法律规章并严格执行。

融合区块链与联邦学习的网络入侵检测算法

任涛 1 ,金若辰 1 ,罗咏梅 2 (1. 东北大学软件学院,沈阳 110169;2. 天津大学智能与计算学部,天津 300072)

本文贡献

文章提出一种融合区块链的联邦学习机制(BFL),采用区块链网络替代中央服务器构建新型联邦学习模式。结合 BFL 机制,设计面向轻量级网络设备的入侵检测算法**(BFL-IDS)**,克服联邦学习过于依赖单一服务器的缺点,避免联邦学习的服务器单点故障问题。实验表明,该算法的分类正确率可以达到 98.8%。进一步,在网络入侵数据检测分析框架中引入了麻雀搜索算法优化的支持向量机,改进后的入侵检测分析方法结果相比传统搜索算法检测准确率提高 5.01%,误报率降低 6.24%。

融合区块链的联邦学习

在服务器端,每个路由器设备都有与其相关联的服务器设备(又称节点),与路由器设备相连的所有节点共同构成区块链。节点在收到各路由器设备上传的参数更新后,通过比较样本大小以及相应的本地计算时间来验证参数更新的真实性,验证通过的更新参数被存储在节点候选块中。每个区块分为头部和主体两部分 :头部存放指向前一个块的指针信息,主体存放 设备的本地模型更新。每个节点都有一个候选块,其中包含来自相关联的本地设备或其他节点的模型更新, 候选块的填充过程一直进行,直到候选块达到预定块大小或者超出等待时间。

结合PoS、BFT和VRF的基于可验证随机函数的拜占庭共识机制(VBFT)能够抵抗恶意攻击,去中心化程度和安全性高,实现了网络的快速共识。本文采用VBFT共识,其中每个区块的VRF值根据前一个区块计算得到,具体过程为提取前一个区块中的交易事务,计算1024bit的哈希值并将该哈希值作为输出。系统将网络分为共识网络和公共网络。用户通过质押代币后参与到共识网络,共识合约自动更新共识节点列表和相应权益(PoS表),每产生一个区块更新一次。每一个区块决定了VRF函数的一个输出,由VRF函数确定共识节点序列,根据节点序列分配优先级,然后通过节点优先级加权决定区块优先级,最后投票给优先级最高的区块,从而解决分叉问题。

联邦学习框架:

区块链学习笔记

BFL模型训练过程

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

给TA打赏
共{{data.count}}人
人已打赏
区块链推广

BIP 入门

2021-11-8 10:51:13

区块链推广

认识区块链,认知区块链——百花争鸣

2021-11-8 10:51:15

重要说明

本站资源大多来自网络,如有侵犯你的权益请联系管理员 区块链Bi站  或给邮箱发送邮件834379394@qq.com 我们会第一时间进行审核删除。 站内资源为网友个人学习或测试研究使用,未经原版权作者许可,禁止用于任何商业途径!请在下载24小时内删除!


如果你遇到支付完成,找不到下载链接,或者不能下载,或者解压失败,先不要忙,加客服主的QQ:834379394 (客服有可能有事情或者在睡觉不能及时的回复您,QQ留言后,请耐心等待即可!)

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索