调试以太坊源代码
⑴ 【深度知识】以太坊数据序列化RLP编码/解码原理
RLP(Recursive Length Prefix),中文翻译过来叫递归长度前缀编码,它是以太坊序列化所采用的编码方式。RLP主要用于以太坊中数据的网络传输和持久化存储。
对象序列化方法有很多种,常见的像JSON编码,但是JSON有个明显的缺点:编码结果比较大。例如有如下的结构:
变量s序列化的结果是{"name":"icattlecoder","sex":"male"},字符串长度35,实际有效数据是icattlecoder 和male,共计16个字节,我们可以看到JSON的序列化时引入了太多的冗余信息。假设以太坊采用JSON来序列化,那么本来50GB的区块链可能现在就要100GB,当然实际没这么简单。
所以,以太坊需要设计一种结果更小的编码方法。
RLP编码的定义只处理两类数据:一类是字符串(例如字节数组),一类是列表。字符串指的是一串二进制数据,列表是一个嵌套递归的结构,里面可以包含字符串和列表,例如["cat",["puppy","cow"],"horse",[[]],"pig",[""],"sheep"]就是一个复杂的列表。其他类型的数据需要转成以上的两类,转换的规则不是RLP编码定义的,可以根据自己的规则转换,例如struct可以转成列表,int可以转成二进制(属于字符串一类),以太坊中整数都以大端形式存储。
从RLP编码的名字可以看出它的特点:一个是递归,被编码的数据是递归的结构,编码算法也是递归进行处理的;二是长度前缀,也就是RLP编码都带有一个前缀,这个前缀是跟被编码数据的长度相关的,从下面的编码规则中可以看出这一点。
对于值在[0, 127]之间的单个字节,其编码是其本身。
例1:a的编码是97。
如果byte数组长度l <= 55,编码的结果是数组本身,再加上128+l作为前缀。
例2:空字符串编码是128,即128 = 128 + 0。
例3:abc编码结果是131 97 98 99,其中131=128+len("abc"),97 98 99依次是a b c。
如果数组长度大于55, 编码结果第一个是183加数组长度的编码的长度,然后是数组长度的本身的编码,最后是byte数组的编码。
请把上面的规则多读几篇,特别是数组长度的编码的长度。
例4:编码下面这段字符串:
The length of this sentence is more than 55 bytes, I know it because I pre-designed it
这段字符串共86个字节,而86的编码只需要一个字节,那就是它自己,因此,编码的结果如下:
184 86 84 104 101 32 108 101 110 103 116 104 32 111 102 32 116 104 105 115 32 115 101 110 116 101 110 99 101 32 105 115 32 109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116 101 115 44 32 73 32 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32 112 114 101 45 100 101 115 105 103 110 101 100 32 105 116
其中前三个字节的计算方式如下:
184 = 183 + 1,因为数组长度86编码后仅占用一个字节。
86即数组长度86
84是T的编码
例5:编码一个重复1024次"a"的字符串,其结果为:185 4 0 97 97 97 97 97 97 ...。
1024按 big endian编码为004 0,省略掉前面的零,长度为2,因此185 = 183 + 2。
规则1~3定义了byte数组的编码方案,下面介绍列表的编码规则。在此之前,我们先定义列表长度是指子列表编码后的长度之和。
如果列表长度小于55,编码结果第一位是192加列表长度的编码的长度,然后依次连接各子列表的编码。
注意规则4本身是递归定义的。
例6:["abc", "def"]的编码结果是200 131 97 98 99 131 100 101 102。
其中abc的编码为131 97 98 99,def的编码为131 100 101 102。两个子字符串的编码后总长度是8,因此编码结果第一位计算得出:192 + 8 = 200。
如果列表长度超过55,编码结果第一位是247加列表长度的编码长度,然后是列表长度本身的编码,最后依次连接各子列表的编码。
规则5本身也是递归定义的,和规则3相似。
例7:
["The length of this sentence is more than 55 bytes, ", "I know it because I pre-designed it"]
的编码结果是:
248 88 179 84 104 101 32 108 101 110 103 116 104 32 111 102 32 116 104 105 115 32 115 101 110 116 101 110 99 101 32 105 115 32 109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116 101 115 44 32 163 73 32 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32 112 114 101 45 100 101 115 105 103 110 101 100 32 105 116
其中前两个字节的计算方式如下:
248 = 247 +1
88 = 86 + 2,在规则3的示例中,长度为86,而在此例中,由于有两个子字符串,每个子字符串本身的长度的编码各占1字节,因此总共占2字节。
第3个字节179依据规则2得出179 = 128 + 51
第55个字节163同样依据规则2得出163 = 128 + 35
例8:最后我们再来看个稍复杂点的例子以加深理解递归长度前缀,
["abc",["The length of this sentence is more than 55 bytes, ", "I know it because I pre-designed it"]]
编码结果是:
248 94 131 97 98 99 248 88 179 84 104 101 32 108 101 110 103 116 104 32 111 102 32 116 104 105 115 32 115 101 110 116 101 110 99 101 32 105 115 32 109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116 101 115 44 32 163 73 32 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32 112 114 101 45 100 101 115 105 103 110 101 100 32 105 116
列表第一项字符串abc根据规则2,编码结果为131 97 98 99,长度为4。
列表第二项也是一个列表项:
["The length of this sentence is more than 55 bytes, ", "I know it because I pre-designed it"]
根据规则5,结果为
248 88 179 84 104 101 32 108 101 110 103 116 104 32 111 102 32 116 104 105 115 32 115 101 110 116 101 110 99 101 32 105 115 32 109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116 101 115 44 32 163 73 32 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32 112 114 101 45 100 101 115 105 103 110 101 100 32 105 116
长度为90,因此,整个列表的编码结果第二位是90 + 4 = 94, 占用1个字节,第一位247 + 1 = 248
以上5条就是RPL的全部编码规则。
各语言在具体实现RLP编码时,首先需要将对像映射成byte数组或列表两种形式。以go语言编码struct为例,会将其映射为列表,例如Student这个对象处理成列表["icattlecoder","male"]
如果编码map类型,可以采用以下列表形式:
[["",""],["",""],["",""]]
解码时,首先根据编码结果第一个字节f的大小,执行以下的规则判断:
1.如果f∈ [0,128),那么它是一个字节本身。
2.如果f∈[128,184),那么它是一个长度不超过55的byte数组,数组的长度为 l=f-128
3.如果f∈[184,192),那么它是一个长度超过55的数组,长度本身的编码长度ll=f-183,然后从第二个字节开始读取长度为ll的bytes,按照BigEndian编码成整数l,l即为数组的长度。
4.如果f∈(192,247],那么它是一个编码后总长度不超过55的列表,列表长度为l=f-192。递归使用规则1~4进行解码。
5.如果f∈(247,256],那么它是编码后长度大于55的列表,其长度本身的编码长度ll=f-247,然后从第二个字节读取长度为ll的bytes,按BigEndian编码成整数l,l即为子列表长度。然后递归根据解码规则进行解码。
以上解释了什么叫递归长度前缀编码,这个名字本身很好的解释了编码规则。
(1) 以太坊源码学习—RLP编码( https://segmentfault.com/a/1190000011763339 )
(2)简单分析RLP编码原理
( https://blog.csdn.net/itchosen/article/details/78183991 )
⑵ 以太坊源码(01):P2P网络及节点发现机制
本文深入探讨以太坊底层的P2P网络结构及其核心机制Kademlia网络,简称Kad。以太坊采用Kad实现分布式网络,此技术由美国纽约大学的研究人员于2002年提出,广泛应用于BitTorrent、BitComet、Emule等软件。
Kad网络中,节点间距离计算遵循异或运算原则。节点间通信基于UDP,主要通过PING-PONG握手确认节点在线。这种设计确保了网络中数据的高效传输。
在以太坊网络中,节点距离的计算方法如下:节点1与节点2间距离=节点1的节点ID与节点2的节点ID进行异或运算的结果。这使得Kad网络能够实现高效的数据查找与定位。
以太坊的Kad网络使用称为K桶的数据结构构建路由表,K桶内存储节点ID、距离、端点、IP等信息。网络中节点距离按照与目标节点的距离进行排序,共有256个K桶,每个K桶包含16个节点。该设计有助于提升网络查找性能与效率。
以太坊的Kad网络节点发现机制基于邻居节点。系统启动时随机生成本机节点ID,之后通过PING-PONG握手将公共节点信息加入K桶。系统每隔7200毫秒刷新K桶,确保网络信息的实时更新。
邻居节点发现流程包含以下几个关键步骤:随机生成目标节点ID,计算目标节点与本地节点的距离,查找距离目标节点更近的K桶节点,向这些节点发送FindNODE命令。接收到命令的节点同样执行类似过程,最终将找到的节点信息返回至本地节点,完成邻居节点的更新。
以太坊Kad网络的邻居节点网络拓扑具有动态特性,允许网络在不断变化中保持高效与稳定。这种机制确保了以太坊网络的高可用性与数据传输的可靠性。
相比传统Kad网络,以太坊Kad网络在实现与优化方面具有独特之处,为构建去中心化、高效、稳定的区块链网络提供了有力支持。
⑶ 什么是以太坊
以太坊是一种区块链技术平台。
以太坊是一个开放源代码的区块链,它被设计为支持智能合约的公有链。下面进行详细解释:
基本定义:
以太坊是一种区块链技术协议,其目的是提供一个去中心化的全球平台,允许各种加密货币和智能合约进行交互。它允许开发者在其平台上建立和部署去中心化应用。这些应用可以在以太坊网络上进行各种操作,如数字身份验证、货币交易等。以太坊的核心特性是智能合约功能,即合约的自动执行,确保了交易的安全性和不可篡改性。通过这种方式,以太坊技术能为用户提供更高效、更安全的金融服务和其他数字服务。
技术特点:
以太坊采用了区块链技术,这意味着它是一个分布式数据库,不包含中央控制或单一的管理员。其交易记录公开透明,全网可查询。由于使用加密算法保护数据,以太坊的交易具有极高的安全性。此外,由于智能合约的存在,以太坊能够实现更复杂的业务逻辑和操作,如资产代币化、投票系统等。开发者可以使用特定的编程语言在以太坊上编写和部署智能合约,进而创建去中心化的应用。随着生态系统的不断完善和发展,以太坊已成为区块链技术领域最受欢迎的开源平台之一。
生态发展与应用前景:
随着时间的推移,以太坊生态系统已经吸引了大量的开发者和企业加入其中。越来越多的项目和应用程序都在使用以太坊的智能合约功能,实现了从数字身份到金融交易等各种应用场更加丰富的业务场景的实现提供了可能性。由于其开源和灵活的特性,以及日益扩大的社区支持,以太坊正逐步成为区块链行业的主导力量之一,未来将有更广泛的应用前景。同时随着技术的不断进步和应用场景的不断拓展以太坊的安全性、可扩展性和用户体验将得到进一步提升满足更多用户需求为构建一个更加高效、去中心化的互联网基础设施做出贡献。
综上所述以太坊作为一种区块链技术平台通过智能合约等特性为全球范围内的交易提供了更加安全、高效的服务并拥有广阔的应用前景和发展空间。
⑷ 死磕以太坊源码分析之挖矿流程
以太坊的挖矿流程主要由miner包负责,它通过miner对象来管理操作,内部使用worker对象实现整体功能。miner决定矿工的启动与停止,并能设置矿工地址以获取奖励。
worker.go文件中的worker对象负责挖矿的细节,其工作流程包含四个主要循环,通过多个channel完成任务调度、新任务提交、任务结果处理等。
新任务由newWorkLoop循环产生,此过程中,resubmitAdjustCh与resubmitIntervalCh两个辅助信号用于调整计时器的频率,resubmitAdjustCh根据历史情况计算合理的间隔时间,而resubmitIntervalCh则允许外部实时修改间隔时间。
mainLoop循环则负责提交新任务并处理结果。TaskLoop提交任务,resultLoop则在新块成功生成后执行相关操作。
启动挖矿的参数设置定义在cmd/utils/flags.go文件中,提供了一系列选项,如开启自动挖矿、设置并行PoW计算的协程数、配置挖矿通知、控制区块验证、设置Gas价格、确定Gas上限、指定挖矿奖励账户、自定义区块头额外数据、设置重新挖矿间隔等。
可以采用多种方式启动挖矿,例如通过控制台命令、RPC接口等。设置参数时,可参考官方文档或相关指南进行调整。
分析代码从miner.go的New函数开始,初始化canStart状态以控制挖矿流程。若Downloader模块正在同步或已完成,则启动挖矿,否则停止。随后进入mainLoop处理startCh,清除旧任务、提交新任务。
生成新任务通过newWorkCh完成,进入CommitNewWork函数,其中包含组装header、初始化共识字段、创建挖矿环境、添加叔块等步骤。添加叔块时进行校验,确保区块符合规定。若条件允许,任务会提交空块、填充交易,并执行交易以生成最终块。
交易执行成功后,块数据被存入数据库,并广播至网络。若执行出错,则回滚至上一个快照状态。成功出块后,新区块被验证、确认,并纳入未确认区块集中。若新区块稳定,将正式插入链中。
整个挖矿流程相对简单,主要由四个循环相互协作完成从挖矿启动到新任务生成、任务提交、成功出块的全过程。共识处理细节将在后续文章中详细阐述。
⑸ 以太坊是什么
以太坊是一种去中心化的区块链技术平台。它提供了一个智能合约和去中心化应用的平台,允许开发者在其上建立和部署各种应用。以太坊利用区块链技术,实现了去中心化、高度安全和不可篡改的特性。以下是详细解释:
一、基本概念
以太坊是一个开源的区块链平台,旨在为全球用户提供一种便捷的方式来创建、部署和管理去中心化应用。这个平台通过智能合约的功能,使得开发者可以在其上编写和运行各种应用程序代码。这些智能合约自动执行、验证和存储交易,而不需要任何第三方的参与。
二、技术特点
以太坊的技术架构包括区块链、以太坊虚拟机和智能合约等关键部分。区块链负责记录所有交易和状态变更,确保数据的不可篡改性。以太坊虚拟机则提供了一个运行智能合约的环境,确保代码的可靠执行。智能合约是用户自定义的业务逻辑代码,可以在以太坊平台上部署和执行。
三、应用前景
由于以太坊的开放性和灵活性,它吸引了大量的开发者和创新者在其上开发各种应用。这些应用包括数字货币、去中心化金融、非同质化代币等。以太坊的生态系统还允许创建各种新的业务模式和服务,推动了区块链技术的广泛应用和发展。
总的来说,以太坊是一个强大的区块链技术平台,为开发者提供了一个构建去中心化应用的生态系统。其智能合约功能和开放源代码模型使得开发者可以方便地创建和部署各种应用,推动了区块链技术的发展和应用。