Hello World - 2019年8月
type: channel
link: http://47.76.222.76/index.php/2019/08
description: Just So So ...
items: 以太坊 事件和日志
items: 区块链 侧链
items: 区块链 分片
items: 分布式一致性
items: 区块链 基础
items: 以太坊 数据结构
items: 以太坊 网络架构
items: 以太坊 目录结构
items: 以太坊 RLP
items: 以太坊 MPT树

以太坊 事件和日志
type: item
date: 2019-08-29T07:50:00+00:00
description: 一、事件事件是以太坊提供的一种链内链外沟通的一种机制。通过触发事件，智能合约可以通知链外组件某个交易完成了什么事儿。下面是一个ERC20合约里常见的Transfer事件定义，通过event关键字表明这是一个事件定义声明。event Transfer(address indexed from, address indexed to, uint256 value);在transfer方法的实现中，我们会像下面代码里展示的这样通过emit关键字触发事件的发生。function transfer(address _to, uint256 _value) public returns (bool) { ... emit Transfer(msg.sender, _to, _value); return true; }二、日志在以太坊的语境里，日志代表对事件的存储。在下面的交易回执里，我们可以看到logs数据项，这个就是我们这里所说的日志，合约执行时每触发一次事件，在交易收据里的logs数据项数组里就会多一个日志条目出来。>eth.getTransactionReceipt("0xe03fac05ff4dde83fc9267184fd8c08bd78599f950e817dbf7fa4a4d4d319ce2"); { blockHash: "0x7eaf6abe64592d10828e136635aa6be6f4d09da3bb5b9fddf87773ee152d657c", blockNumber: 4654718, contractAddress: null, cumulativeGasUsed: 52464, from: "0x076979a0b3c87334e5d72e3afcafaa80f7888cac", gasUsed: 52464, logs: [{ address: "0x73c2a5b1a32fa8e33101a6ab119203f4417feae4", blockHash: "0x7eaf6abe64592d10828e136635aa6be6f4d09da3bb5b9fddf87773ee152d657c", blockNumber: 4654718, data: "0x0000000000000000000000000000000000000000000000056bc75e2d63100000", logIndex: 0, removed: false, topics: ["0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef", "0x000000000000000000000000076979a0b3c87334e5d72e3afcafaa80f7888cac", "0x000000000000000000000000cd9f286ba6a3d2df7885f4a2be267fc524d32bd3"], transactionHash: "0xe03fac05ff4dde83fc9267184fd8c08bd78599f950e817dbf7fa4a4d4d319ce2", transactionIndex: 0 }], logsBloom: "0x20000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000080000008000000000400000000000000000000000000000000000000040000000000000000100000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000200000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000400", status: "0x1", to: "0x73c2a5b1a32fa8e33101a6ab119203f4417feae4", transactionHash: "0xe…

区块链 侧链
type: item
date: 2019-08-26T02:11:00+00:00
description: 虽然区块链技术目前正在快速发展，但是传统区块链技术要落地到商业应用，特别是金融应用，仍然存在很多问题需要解决，如交易性能、隐私保护等。解决这些问题的一种做法是重新开发新的区块链，但是这种做法会造成大量重复性工作，并且需要不断的发行新的数字资产。那么是否存在在不影响原有区块链工作的基础上，依托于原有区块链进行技术升级的解决方案，侧链就是在这种需求背景下被提出的。基础概念侧链协议本质上是一种跨区块链解决方案。通过这种解决方案，可以实现数字资产从第一个区块链到第二个区块链的转移，又可以在稍后的时间点从第二个区块链安全返回到第一个区块链。其中第一个区块链通常被称为主区块链或者主链，每二个区块链则被称为侧链。最初，主链通常指的是比特币区块链，而现在主链可以是任何区块链。侧链协议被设想为一种允许数字资产在主链与侧链之间进行转移的方式，这种技术为开发区块链技术的新型应用和实验打开了一扇大门。产生背景2012年，在比特币聊天室中，首次出现了关于侧链概念的相关讨论。当时比特币的核心开发团队正在考虑如何可以安全的升级比特币协议，以增加新的功能，但是直接在比特币区块链上进行功能添加比较危险，因为如果新功能在实践中发生软件故障，则会对现有的比特币网络造成严重影响。另外，由于比特币的网络结构特性，如果进行较大规模的改动，还需要获得多数比特币矿工的支持。这时，比特币核心开发者便提出了侧链方案。这种技术允许开发人员将新功能附加在其他的区块链，但是这些区块链仍然附着在现有比特币区块链上。这些区块链中新功能可以充分利用现有比特币的网络特性，而不会对现有的比特币网络造成危害。2014年，这时已经出现了许多具有新功能的区块链，并产生了各种竞争币，如莱特币、狗狗币等。这时，比特币的核心开发团队担心这些竞争币的产生会稀释比特币的价值。他们认为，应该把比特币作为一种储备货币，并将新功能添加到侧链上。这样如果用户想使用其他的新的区块链功能，就不需要购买其他代币。为了将侧链由概念转化成现实，Adam Back、Matt Corallo等比特币核心开发者共同发起成立了Blockstream公司，并在同年十月，发布了白皮书《Enabling Blockchain Innovations with Pegged Sidechains》，首次明确提出了侧链的概念及其协议实现方案。通过侧链，可以在主链的基础上，进行交易隐私保护技术、智能合约等新功能的添加，这样可以让用户访问大量的新型服务，并且对现有主链的工作并不造成影响。另外，侧链也提供了一种更安全的协议升级方式，当侧链发生灾难性的问题时，主链依然安然无恙。实现方案侧链实现的技术基础是双向锚定（Two-way Peg），通过双向锚定技术，可以实现暂时的将数字资产在主链中锁定，同时将等价的数字资产在侧链中释放，同样当等价的数字资产在侧链中被锁定的时候，主链的数字资产也可以被释放。双向锚定实现的最大难点是协议改造需兼容现有主链，也就是不能对现有主链的工作造成影响，其具体实现方式可以分为以下几类：（一）单一托管模式最简单的实现主链与侧链双向锚定的方法就是通过将数字资产发送到一个主链单一托管方（类似于交易所），当单一托管方收到相关信息后，就在侧链上激活相应数字资产。这个解决方案的最大问题是过于中心化。比特币为主链的单一托管模式的工作原理示意图：（二）联盟模式联盟模式是使用公证人联盟来取代单一的保管方，利用公证人联盟的多重签名对侧链的数字资产流动进行确认。在这种模式中，如果要想盗窃主链上冻结的数字资产就需要突破更多的机构，但是侧链安全仍然取决于公证人联盟的诚实度。以比特币为主链的联盟模式的工作示意图：单一托管模式与联盟模式的最大优点是它们不需要对现有的比特币协议进行任何的改变。（三）SPV模式SPV（Simplified Payment Verification）模式是最初的侧链白皮书《Enabling Blockchain Innovations with Pegged Sidechains》中的去中心化双向锚定技术最初设想。SPV是一种用于证明交易存在的方法，通过少量数据就可以验证某个特定区块中交易是否存在。在SPV模式中，用户在主链上将数字资产发送到主链的一个特殊的地址，这样做会锁定主链的数字资产，该输出仍然会被锁定在可能的竞争期间内，以确认相应的交易已经完成，随后会创建一个SPV证明并发送到侧链上。此刻，一个对应的带有SPV证明的交易会出现在侧链上，同时验证主链上的数字资产已经被锁住，然后就可以在侧链上打开具有相同价值的另一种数字资产。这种数字资产的使用和改变在稍后会被送回主链。当这种数字资产返回到主链上时，该过程会进行重复。它们被发送到侧链上锁定的输出中，在一定的等待时间后，就可以创建一个SPV证明，来将其发送回主区块链上，以解锁主…

区块链 分片
type: item
date: 2019-08-25T14:06:00+00:00
description: 进行区块链扩容的一个答案就是分片技术（Sharding）。分片技术承诺通过改变网络验证的方式来增加吞吐量。分片技术独特于其他解决扩容的链上技术的关键特性，就是它可以进行水平扩容，也就是说，网络的吞吐量随着挖矿网络的扩展而增加。这种特殊的特性可能使它成为推动区块链技术被快速采用的理想技术。简单来说，分片技术就是一个分散式并行系统，在保持主链完整稳定的同时，减少每个节点的数据储存量，从而达到扩容的效果。现有区块链的扩容问题公共区块链平台今天面临的最大问题之一就是可扩展性。所有主流的平台都在努力提高每秒的交易量。事实上，当今的公共以太坊网络和比特币网络平均每秒可以处理7-10笔交易。这一数字远低于像Visa这样的集中支付处理器，后者平均每秒能处理约8000笔交易。缓慢的交易处理造成了一个主要问题，因为大量的未完成交易阻塞了网络，使得那些诸如实时支付这样的应用程序很难在区块链上一展身手。随着确认支付的时间拉长，最终就会给用户带来诸多不便；这也是为什么像PayPal和Visa这样的信用卡支付方式仍然更具吸引力的主要原因之一。随着更多更复杂的DApps开始依赖于相同的一个区块链网络，迟缓的交易速度所导致的问题只会变得更加复杂。从技术角度来看，所有区块链的共识协议都有一个具有挑战性的限制：网络中的每一个完全参与的节点都必须要验证每一笔交易，并且这些节点必须和它的其他节点保持一致，这是区块链技术的组成部分，它通过创建分布式的账本来保证区块链的安全。在大多数像比特币和以太坊这样的区块链上，节点都是由公众进行运行的。虽然去中心化的共识机制提供了一些重要的优势，比如容错性、安全性、政治中立和真实性，但是这种验证链的方法是以降低可扩展性为代价的。当这些公共区块链变得更大时，它将需要越来越多的处理能力来验证这些公共区块链，这可能会在这些区块链的网络中造成瓶颈，从而减慢那些创建新应用程序的速度。分片技术：分而治之分片技术是一种基于数据库分片传统概念的扩容技术，它将数据库分割成多个碎片并将这些碎片放置在不同的服务器上。在公共区块链的情境中，网络上的交易将被分成不同的碎片，其由网络上的不同节点组成。因此，每个节点只需处理一小部分传入的交易，并且通过与网络上的其他节点并行处理就能完成大量的验证工作。将网络分割为碎片会使得更多的交易同时被处理和验证。因此，随着网络的增长，区块链处理越来越多的交易将成为可能。这种属性也称为水平扩容。我们可以想象一下，现有的区块链就像一条繁忙的高速公路，这条高速公路的收费站只有一个收费口。这种布局的结果将是导致交通堵塞，因为人们将排着长队等待通过这唯一的收费站。实现一个基于分片技术的区块链就像在高速公路上增加15或20个收费口。它将极大地提高汽车通过收费站的速度。因此，分片技术将带来巨大的差异，并显著提高区块链的交易速度。基于分片技术的区块链的实现对公共区块链有着不同的好处。首先，区块链上处理交易的速度变成了每秒上千笔甚至更多，这改变了人们对加密货币作为支付方式效率的看法。改善交易吞吐量将会给去中心化的系统带来使越来越多的用户和应用程序，而这将反过来促进区块链的进一步采用，也使挖矿变得更有利可图，同时也能吸引更多加入到公共网络上的节点，从而形成一个良性循环。此外，分片技术可以帮助降低交易费用，因为验证单笔交易的处理量减少了；节点可以在依然盈利运营的同时收取较小的费用。在现实世界中，我们将低费用与高交易处理能力结合起来，会使公共链将变得越来越有吸引力。这些积极的趋势所持续的时间越长，我们就会越能看到更多的主流的加密技术和区块链应用程序的出现。分片技术的策略分片策略有网络分片和交易分片，以及状态分片等。通过网络和交易分片，区块链节点的网络被分割成不同的碎片，每个碎片都能形成独立的处理过程并在不同的交易子集上达成共识。通过这种方式，我们可以并行处理相互之间未建立连接的交易子集，通过提高数量级显著提高交易的吞吐量。另一方面，在当今的主流公共区块链上，所有公共节点都承担着存储交易、智能合约和各种状态的负担，这可能使其在为了获得更大的存储空间而进行巨大的花费，以维持其在区块链上的正常运转。为了解决这一问题，有一种可被称为状态分片的可行方法已被提出。这一技术的关键是将整个存储区分开，让不同的碎片存储不同的部分；因此，每个节点只负责托管自己的分片数据，而不是存储完整的区块链状态。分片技术的复杂性尽管所有不同形式的分片技术都可能非常直观，但通过对技术细节的解读，我们可以看到这一方法的复杂性和潜在的挑战。分片技术的其中一些挑战是很容易克服的，而另一些则不然。一般来说，网络和交易分片更容易实现，而状态分片则要复杂得多。下面，对于不同的分片机制，我们会明确地讨论它们所面临的一些挑战，以及它们的可行性。1、网络分片：如何将全网节点划分到不同分片当中去分片的第…

分布式一致性
type: item
date: 2019-08-25T11:09:48+00:00
description: 分布式系统一致性 一致性即是对于系统中的多个服务节点，在约定的协议下，执行相同的操作并保持状态的一致，简单来说就是多个节点持有相同的数据，如果数据要改变就应该每一个节点都做相同的改变。如果分布式系统能实现“一致”，对外就可以呈现为一个功能正常的，且性能和稳定性都要好很多的“虚处理节点”。 理想的分布式系统一致性应该满足：可终止性（Termination）、共识性（Consensus）、合法性（Validity）。一致性难题但是在实际的计算机集群中，可能会存在以下问题:节点之间的网络通讯是不可靠的，包括数据丢失、延迟、重复、损坏节点处理事务的能力不同，网络节点数据的吞吐量有差异节点可能死记，可能会有作恶节点出现当异步处理能力达到高度一致时，系统的可扩展性就会变差,即容不下新节点的加入弱一致性可想而知，绝对理想的强一致性（Strong Consistency）代价很大。除非不发生任何故障，所有节点之间的通信无需任何时间，这个时候其实就等价于一台机器了。实际上，越强的一致性要求往往意味着越弱的性能 强一致的系统往往比较难实现。很多时候，人们发现实际需求并没有那么强，可以适当放宽一致性要求，降低系统实现的难度。例如在一定约束下实现所谓最终一致性（Eventual Consistency），即总会存在一个时刻（而不是立刻），系统达到一致的状态，这一类弱化的一致性，被笼统称为弱一致性（Weak Consistency）一致性级别强一致性, 这种一致性级别是最符合用户直觉的，它要求系统写入什么，读出来的也会是什么，用户体验好，但实现起来往往对系统的性能影响大 弱一致性, 这种一致性级别约束了系统在写入成功后，不承诺立即可以读到写入的值，也不久承诺多久之后数据能够达到一致，但会尽可能地保证到某个时间级别（比如秒级别）后，数据能够达到一致状态 最终一致性, 最终一致性是弱一致性的一个特例，系统会保证在一定时间内，能够达到一个数据一致的状态。这里之所以将最终一致性单独提出来，是因为它是弱一致性中非常推崇的一种一致性模型，也是业界在大型分布式系统的数据一致性上比较推崇的模型共识算法实际上，要保障系统满足不同程度的一致性，往往需要通过共识算法来达成。共识算法解决的是对某个提案（Proposal），大家达成一致意见的过程。提案的含义在分布式系统中十分宽泛，如多个事件发生的顺序、某个键对应的值、谁是领导……等等，可以认为任何需要达成一致的信息都是一个提案。 “完美”的系统并不存在，响应请求往往存在时延、网络会发生中断、节点会发生故障、甚至存在恶意节点故意要破坏系统。一般地，把故障（不响应）的情况称为“非拜占庭错误”，恶意响应的情况称为“拜占庭错误”。 针对非拜占庭错误的情况，一般包括Paxos、Raft、zab 及其变种。对于要能容忍拜占庭错误的情况，一般包括 PBFT、PoW、Pos算法等。共识界限一般情况下，分布式系统的共识问题无解。当节点之间的通信网络自身不可靠情况下，很显然，无法确保实现共识。但好在，一个设计得当的网络可以在大概率上实现可靠的通信。然而，即便在网络通信可靠情况下，一个可扩展的分布式系统的共识问题的下限是无解。这个结论，被称为FLP不可能性原理。FLP 不可能原理实际上告诉人们，不要浪费时间去为异步分布式系统设计在任意场景下都能实现共识的算法。FLP不可能性原理：在网络可靠，存在节点失效（即便只有一个）的最小化异步模型系统中，不存在一个可以解决一致性问题的确定性算法。在付出一些代价的情况下，可以设计出一个大致可用的共识算法，这就是CAP理论。CAP理论：分布式计算系统不可能同时确保一致性（Consistency）、可用性（Availablity）和分区容忍性（Partition），设计中往往需要弱化对某个特性的保证。一致性（Consistency）：任何操作应该都是原子的，发生在后面的事件能看到前面事件发生导致的结果，注意这里指的是强性； 可用性（Availablity）：在有限时间内，任何非失败节点都能应求； 分区容忍性（Partition）：网络可能发生分区，即节点之间的通信不可保障。BASE理论BASE是Basically Available（基本可用）、Soft state（软状态）和Eventually consistent（最终一致性）三个短语的缩写。BASE理论是对CAP中一致性和可用性权衡的结果，其来源于对大规模互联网系统分布式实践的总结， 是基于CAP定理逐步演化而来的。BASE理论的核心思想是：即使无法做到强一致性，但每个应用都可以根据自身业务特点，采用适当的方式来使系统达到最终一致性。基本可用 基本可用是指分布式系统在出现不可预知故障的时候，允许损失部分可用性----注意，这绝不等价于系统不可用。比如： 软状态…

区块链 基础
type: item
date: 2019-08-24T15:58:00+00:00
description: 区块链是分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式，它本质上是一个去中心化的分布式数据库，是一串相关联的使用密码学方法产生的的数据区块。比特币白皮书英文原版其实并未出现blockchain一词，而是使用的chain of blocks。最早的比特币白皮书中文翻译版中，将chain of blocks翻译成了区块链。这是“区块链”这一中文词最早的出现时间。狭义来讲，区块链是一种按照时间顺序将数据区块以顺序相连的方式组合成的一种链式数据结构，并以密码学方式保证的不可篡改和不可伪造的分布式账本。广义来讲，区块链技术是利用块链式数据结构来验证与存储数据、利用分布式节点共识算法来生成和更新数据、利用密码学的方式保证数据传输和访问的安全、利用由自动化脚本代码组成的智能合约来编程和操作数据的一种全新的分布式基础架构与计算方式。区块链技术被认为是继蒸汽机、电力、互联网之后，下一代颠覆性的核心技术。 如果说蒸汽机释放了人们的生产力，电力解决了人们基本的生活需求，互联网彻底改变了信息传递的方式，那么区块链作为构造信任的机器，将可能彻底改变整个人类社会价值传递的方式。基本原理区块链包括三个基本概念：交易（transaction）：一次对账本的操作，导致账本状态的一次改变，如添加一条转账记录；区块（block）：记录一段时间内发生的所有交易和状态结果，是对当前账本状态的一次共识；链（chain）：由区块按照发生顺序串联而成，是整个账本状态变化的日志记录。如果把区块链作为一个状态机，则每次交易就是试图改变一次状态，而每次共识生成的区块，就是参与者对于区块中交易导致状态改变的结果进行确认。在实现上，首先假设存在一个分布式的数据记录账本，这个账本只允许添加、不允许删除。账本底层的基本结构是一个线性的链表，这也是其名字“区块链”的来源。链表由一个个“区块”串联组成，后继区块记录前导区块的哈希值。新的数据要加入，必须放到一个新的区块中。而这个块是否合法，可以通过计算哈希值的方式快速检验出来。任意维护节点都可以提议一个新的合法区块，然而必须经过一定的共识机制来对最终选择的区块达成一致。发展历程2008年由中本聪第一次提出了区块链的概念，在随后的几年中，区块链成为了电子货币比特币的核心组成部分：作为所有交易的公共账簿。通过利用点对点网络和分布式时间戳服务器，区块链数据库能够进行自主管理。为比特币而发明的区块链使它成为第一个解决重复消费问题的数字货币。比特币的设计已经成为其他应用程序的灵感来源。2014年，"区块链2.0”成为一个关于去中心化区块链数据库的术语。对这个第二代可编程区块链，经济学家们认为它是一种编程语言，可以允许用户写出更精密和智能的协议。因此，当利润达到一定程度的时候，就能够从完成的货运订单或者共享证书的分红中获得收益。区块链2.0技术跳过了交易和“价值交换中担任金钱和信息仲裁的中介机构”。它们被用来使人们远离全球化经济，使隐私得到保护，使人们“将掌握的信息兑换成货币”，并且有能力保证知识产权的所有者得到收益。第二代区块链技术使存储个人的“永久数字ID和形象”成为可能，并且对“潜在的社会财富分配”不平等提供解决方案。2016年1月20日，中国人民银行数字货币研讨会宣布对数字货币研究取得阶段性成果。会议肯定了数字货币在降低传统货币发行等方面的价值，并表示央行在探索发行数字货币。中国人民银行数字货币研讨会的表达大大增强了数字货币行业信心。这是继2013年12月5日央行五部委发布关于防范比特币风险的通知之后，第一次对数字货币表示明确的态度。2016年12月20日，数字货币联盟——中国FinTech数字货币联盟及FinTech研究院正式筹建。如今，比特币仍是数字货币的绝对主流，数字货币呈现了百花齐放的状态，常见的有bitcoin、litecoin、dogecoin、dashcoin，除了货币的应用之外，还有各种衍生应用，如以太坊Ethereum、Asch等底层应用开发平台以及NXT，SIA，比特股，MaidSafe，Ripple等行业应用。类型公有区块链公有区块链（Public Block Chains)是指：世界上任何个体或者团体都可以发送交易，且交易能够获得该区块链的有效确认，任何人都可以参与其共识过程。公有区块链是最早的区块链，也是应用最广泛的区块链，各大bitcoins系列的虚拟数字货币均基于公有区块链，世界上有且仅有一条该币种对应的区块链。联合（行业）区块链行业区块链（Consortium Block Chains)：由某个群体内部指定多个预选的节点为记账人，每个块的生成由所有的预选节点共同决定（预选节点参与共识过程），其他接入节点可以参与交易，但不过问记账过程(本质上还是托管记账，只是变成分布式记账，预选节点的多少，…

以太坊 数据结构
type: item
date: 2019-08-22T10:41:00+00:00
description: 一、区块（Block）区块（Block）是以太坊（Ethereum）的核心数据结构之一。所有账户的相关活动，以交易(Transaction)的格式存储，每个区块有一个交易对象的列表；每个交易的执行结果，由一个收据（Receipt）对象与其包含的一组日志（Log）对象记录；所有交易执行完后生成的收据列表，存储在区块中(经过压缩加密)。不同区块之间，通过前向指针父哈希（ParentHash）一个一个串联起来成为一个链表，区块链（BlockChain）结构体管理着这个链表。数据定义：type Block struct { header *Header //区块头 uncles []*Header //叔块头集合 transactions Transactions //交易集合 hash atomic.Value //区块哈希 size atomic.Value //区块大小 td *big.Int //累计的区块难度 ReceivedAt time.Time //区块接收时间 ReceivedFrom interface{} //区块来源 }数据项注解：td（total difficulty）为当前链的总难度，即到当前区块截止，累积的所有区块难度之和核心方法：func (b *Block) Size() common.StorageSize //区块rlp编码后的大小func (b *Block) Hash() common.Hash //区块keccak256哈希，实际是header的哈希1、区块头区块头（Header）是Block的核心，注意到它的成员变量全都是公共的，这使得它可以很方便的向调用者提供关于Block属性的操作。type Header struct { ParentHash common.Hash //父区块哈希。除了创世块外，每个区块有且只有一个父区块 UncleHash common.Hash //所属区块uncles成员的哈希值。uncles是一个Header数组 Coinbase common.Address //打包该区块的矿工的地址，用于接收矿工费 Root common.Hash //状态树的根哈希值 TxHash common.Hash //交易树的根哈希值 ReceiptHash common.Hash //收据树的根哈希值 Bloom Bloom //交易收据日志组成的Bloom过滤器 Difficulty *big.Int //本区块的难度 Number *big.Int //区块的序号。等于其父区块Number+1 GasLimit uint64 //区块内所有Gas消耗的上限，该数值在区块创建时设置，用于限定区块大小。 GasUsed uint64 //区块内所有Transaction执行时所实际消耗的Gas总和 Time uint64 //区块产生的时间戳，一般是打包区块的时间，这个字段不是出块的时间戳 Extra []byte //区块的附加数据 MixDigest common.Hash //哈希值，与Nonce的组合用于工作量计算 Nonce BlockNonce //一个64bit的哈希数，它被应用在区块的"挖掘"阶段，并且在使用中会被修改 }GasLimit是用于限制区块中的交易个数用的。具体由每个矿工自己设置，有些矿工觉得本区块的GasLimit太大，可以在挖下一个区块时间Gas Limit下调1/1024,觉得GasLimit太小的时候，就会上调1/1024。整个区块链中区块的大小，就是所有矿工微调的平均值。以太坊中正是通过GasLimit来限制区块的大小。区块头中比较重要的三个字段是Root、TxHash和ReceiptHash三个哈希值。收据树必须在区块的所有交易执行完成才能生成；交易树理论上只需交易数组即可，不过依然被限制在所有交易执行完后才生成；最有趣的是状态树，由于它存储了所有账户的信息，比如余额，发起交易次数，虚拟机指令数组等等，所以随着每次交易的执行，状态其实一直在变化，这就使得Root值也在变化中。于是StateDB定义了一个函数IntermediateRoot()，用来生成那一时刻的Root值:2、交易区块的成员transactions其实是Transaction数组，交易(Transaction)是指由一个外部账户转移一定资产给某个账户， 或者发出一个消息指令到某个智能合约。在以太坊网络中，交易执行属于一个事务。具有原子性、一致性、隔离性、持久性特点。为了安全性，交易需要发送者签名才有效，别人不能伪造签名发起交易而盗取以太币。需要注意的是，TxByNonceh是按nonce排序的Transaction数组，TxByPrice是按gas价格排序的Trans…

以太坊 网络架构
type: item
date: 2019-08-21T02:10:00+00:00
description: 0x00 前言 {#0x00}区块链的火热程度一直以直线上升，其中以区块链 2.0 —— 以太坊为代表，不断的为传统行业带来革新，同时也推动区块链技术发展。区块链是一种分布式数据存储、点对点传输、共识机制、加密算法等计算机技术的新型应用模式，这是一个典型的去中心化应用，建立在 p2p 网络之上；本文以学习和分析以太坊运作原理为目的，将以太坊网络架构作为一个切入点，逐步深入分析，最终对以太坊网络架构有个大致的了解。通过学习以太坊网络架构，可以更容易的对网络部分的源码进行审计，便于后续的协议分析，来发现未知的安全隐患；除此之外，目前基于 p2p 网络的成熟的应用非常少，借助分析以太坊网络架构的机会，可以学习一套成熟的 p2p 网络运行架构。本文侧重于数据链路的建立和交互，不涉及网络模块中的节点发现、区块同步、广播等功能模块。0x01 目录Geth 启动网络架构共享密钥RLPXFrameRW 帧RLP 编码LES 协议总结其中第 3、4、5 三个小节是第 2 节「网络架构」的子内容，作为详细的补充。0x02 Geth 启动在介绍以太坊网络架构之前，首先简单分析下 Geth 的整体启动流程，便于后续的理解和分析。以太坊源码目录tree -d -L 1 . ├── accounts 账号相关 ├── bmt 实现二叉merkle树 ├── build 编译生成的程序 ├── cmd geth程序主体 ├── common 工具函数库 ├── consensus 共识算法 ├── console 交互式命令 ├── containers docker 支持相关 ├── contracts 合约相关 ├── core 以太坊核心部分 ├── crypto 加密函数库 ├── dashboard 统计 ├── eth 以太坊协议 ├── ethclient 以太坊RPC客户端 ├── ethdb 底层存储 ├── ethstats 统计报告 ├── event 事件处理 ├── internal RPC调用 ├── les 轻量级子协议 ├── light 轻客户端部分功能 ├── log 日志模块 ├── metrics 服务监控相关 ├── miner 挖矿相关 ├── mobile geth的移动端API ├── node 接口节点 ├── p2p p2p网络协议 ├── params 一些预设参数值 ├── rlp RLP系列化格式 ├── rpc RPC接口 ├── signer 签名相关 ├── swarm 分布式存储 ├── tests 以太坊JSON测试 ├── trie Merkle Patricia实现 ├── vendor 一些扩展库 └── whisper 分布式消息 35 directories 初始化工作Geth 的 main() 函数非常的简洁，通过 app.Run() 来启动程序：[./cmd/geth/main.go] func main() { if err := app.Run(os.Args); err != nil { fmt.Fprintln(os.Stderr, err) os.Exit(1) } } 其简洁是得力于 Geth 使用了 gopkg.in/urfave/cli.v1 扩展包，该扩展包用于管理程序的启动，以及命令行解析，其中 app 是该扩展包的一个实例。在 Go 语言中，在有 init() 函数的情况下，会默认先调用 init() 函数，然后再调用 main() 函数；Geth 几乎在 ./cmd/geth/main.go#init() 中完成了所有的初始化操作：设置程序的子命令集，设置程序入口函数等，下面看下init() 函数片段：[./cmd/geth/main.go] func init() { // Initialize the CLI app and start Geth app.Action = geth app.HideVersion = true // we have a command to print the version app.Copyright = "Copyright 2013-2018 The go-ethereum Authors" app.Commands = []cli.Command{ // See chaincmd.go: initCommand, importCommand, exportCommand, importPreimagesCommand, ... } ... } 在以上代码中，预设了 app 实例的值，其中 app.Action = geth 作为 app.Run() 调用的默认函数，而 app.Commands 保存了子命令…

以太坊 目录结构
type: item
date: 2019-08-20T07:04:00+00:00
description: accounts 实现了钱包帐户管理build 编译脚本和配置cmd 命令行工具abigen 合约接口生成bootnode 实现网络发现的引导节点clef 钱包账户管理ethkey 私钥管理evm 以太坊虚拟机geth 以太坊命令行客户端p2psim 提供了一个工具来模拟http的APIpuppeth 创建一个新的以太坊网络的向导rlpdump 提供RLP数据的格式化输出util 命令行公共的组件wnode 一个简单的Whisper节点common 提供了一些公共的工具类consensus 共识协议，包括pow和posconsole 交互式命令core 以太坊核心h数据结构和算法（虚拟机、状态、区块链、）crypto 加密和哈希函数库dashboard 统计eth 以太坊协议ethclient 以太坊RPC客户端ethdb eth的数据库，最底层的存储ethstats 统计报告event 事件处理graphql 节点数据的graphql接口internal RPC调用les 轻量级子协议light 轻客户端部分功能log 日志模块metrics 提供磁盘计数器miner 挖矿相关mobile geth的移动端APInode 接口节点p2p p2p网络协议params 一些预设参数值rlp RLP系列化格式rpc RPC接口signer 签名相关swarm 分布式存储tests 以太坊JSON测试trie MPT树实现vendor 引用扩展库打包whisper 分布式消息协议

以太坊 RLP
type: item
date: 2019-08-15T03:50:00+00:00
description: RLP(Recursive Length Prefix，递归的长度前缀)是一种编码规则，可用于编码任意嵌套的二进制数组数据。RLP编码的结果也是二进制序列。RLP主要用来序列化/反序列化数据。一、RLP数据定义RLP编码的定义只处理以下2类底层数据：字符串（String）是指字节数组列表（List）是指字节数组的数组所有上层类型的数据需要转成以上的2类数据，才能进行RLP编码。转换的规则RLP编码不统一规定，可以自定义转换规则。从上面的数据类型定义中可以看出，RLP编码的数据可看做字节数组和多维变长字节数组。二、编码规则RLP编码的重点是给原始数据前面添加若干字节的前缀，而且这个前缀是和数据的长度相关的，并且是递归的。1.针对单字节b，b ∈ [0,127], Rc(b) = beg:Rc(a) = 97, Rc(w) = 119**2.针对字节数组bytes，length(bytes) <= 55, Rc(bytes) =128+length(bytes) ++ bytes(++符号表示拼接)**eg:Rc(abc) = [131 97 98 99], 其中131 = 128+length(abc), [97 9899]为[abc]本身编码**3.针对字节数组bytes，length(bytes) > 55, Rc(bytes) = 183+sizeof(sizeof(bytes)) ++ Rc(sizeof(bytes)) + bytes**eg: str = "The length of this sentence is more than 55 bytes, I knowit because I pre-designed it" Rc(str) = [184 86 84 104 101 32 108 101 110 103 116 104 32 111102 32 116 104 105 115 32 115 101 110 116 101 110 99 101 32 105 115 32109 111 114 101 32 116 104 97 110 32 53 53 32 98 121 116 101 115 44 3273 32 107 110 111 119 32 105 116 32 98 101 99 97 117 115 101 32 73 32112 114 101 45 100 101 115 105 103 110 101 100 32 105 116] 经计算该字符串占用字节数为86，显然184 = 183 + sizeof(86)，86 =sizeof(str), 84为“T”的编码，从84开始后面便是str本身的编码。以上是针对字节数组，接下来看以字节数组为元素的数组，这里称之为列表的编码方式：首先要明确几个概念，针对一个列表list，lenL是指list内每个bytes字节数的总和，lenDl是指list每个bytes经过Rc(x)编码后的总长度。**lenL(list) =) lenDl(list) =))****4.针对list[bytes0, bytes1...bytesN]，lenL(list) \<= 55,\ Rc(list) = 192+lenDl(list) ++Rc()**eg: list = ["abc", "def"],\ Rc(list) = [200 131 97 98 99 131 100 101 102]\ 首先，lenL(list) = 3+3 \<= 55,\ 然后，根据规则3可以得出：\ Rc[abc] = [131 97 98 99]，\ Rc[def] = 131 100 101 102\ 现在就知道，lenDl(list) = 4 + 4 =8，所以开始的200就是192+8的结构，后面跟的是list里每个bytes的RLP编码。**5.针对list[bytes0, bytes1...bytesN]，lenL(list) \> 55,\ Rc(list) = 247+sizeof(lenDl(list)) ++ lenDl(list) ++Rc()**eg: list = ["The length of this sentence is more than 55 bytes,",\ " I know it because I pre-designed it"]\ Rc(list) = [248 88 179 84 104 101 32 108 101 110 103 116 104 32 111102 32 116 104 105 115 32 115 101 110 116 101 110 99 101 32 105 115 32109 111 …

以太坊 MPT树
type: item
date: 2019-08-14T03:45:00+00:00
description: 引言MPT树（Merkle Patricia Tree）是以太坊中一种非常重要的数据结构，用来存储用户账户的状态及其变更（状态树）、交易信息（交易树）、交易的收据信息（收据树）。它实际上是Merkle Tree和Patricia Tree组合而成的一种树形结构，并且同时具备这两种树的特性和优点。我们期望从原理和源代码两方面入手，以期对其进行深入的了解。实现原理以Patricia Tree为基础，以太坊主要从以下几个方面对其进行了改进和优化。使用[]byte作为key的类型，而非字符串在以太坊的Trie模块中，key和value都是[]byte类型。如果要使用其它类型，需要将其转换成[]byte类型（比如使用rlp进行转换）。当然这不是什么本质上改变，我个人感觉只是为了编码方便吧。因为rlp模块可以方便的把各种结构序列化成[]byte而不是string。nibble: key类型的最小单位其实在以太坊的Trie模块对外提供的接口中，key类型当然是[]byte。但在内部实现里，将key中的每个字节按高4位和低4位拆分成了两个字节。比如你传入的key是：[0x1a, 0x2b, 0x3c, 0x4d]Trie内部将这个key拆分成：[0x1, 0xa, 0x2, 0xb, 0x3, 0xc, 0x4, 0xd]Trie内部的编码中将拆分后的每一个字节称为nibble如果使用一个完整的byte作为key的最小单位，那么前文提到的索引数组的大小应该是256（byte作为数组的索引，最大值为255，最小值为0）。而索引数组的每个元素都是一个32字节的哈希（这在下一条中进行了说明）,这样每个结点要占用大量的空间。并且索引数组中的元素多数情况下是空的，不指向任何结点。因此这种实现方法占用大量空间而不使用。以太坊的改进方法，可以将索引数组的大小降为16（4个bit的最大值为0xF，最小值为0），因此大大减少空间的浪费。使用hash引用结点而不是内存指针在以太坊的实现中，索引数组的每个元素都是下一个结点的hash，而非指针。也就是说，父结点持有的是子结点的hash。这种实现方式使得以太坊中的Trie带有了默克尔树的功能：如果两个Trie的根结点的hash相同，我们就可以断定，这两棵树的内容完全一样。需要注意的是，这种实现也包括对value的引用。也就是说在以太坊的Trie中，遍历到叶子结点以后得到的是value的hash，而非value本身。使用这个hash从数据库中读取出来的值才是value。当树的某条路径没有分支时，使用一个结点存储路径上的所有key我们回看上面介绍字典树的那张图，其中"medicine"这条路径中，除了前三个字符'med'，其它字符都没有分支，因此为了节省空间，以太坊将这种情况下的结点缩减为一个。如下图所示：这样就可以进一步节省空间的开销。但同时也产生了一个问题：对于某个结点，如何知道它存储的是索引数组，还是key的数组呢？以太坊解决这个问题的方式是通过结点元素个数的不同进行区分。以太坊在Trie内部将结点分成了两类：全节点（fullNode）和快捷节点（shortNode）。全节点有17个元素，而快捷结点有两个元素。它们的示意表达如下：全结点： [i0, i2, ... i15, value]快捷结点：[ [k0, k1, ... kn], value ]可以看到全结点由索引数组（共16个元素）和一个value组成（前面说过value的引用也是通过hash，而不是直接存储value的值）；而快捷结点有2个元素，一个是key数组，另一个就是value。此时虽然可以知道一个结点存储的数据的格式，但对于快捷结点，仍有两个问题没有解决。一个问题是，前面说过key的最小单位是nibble，。那么如果在快捷结点中nibble的个数是奇数，它重新组合成[]byte存储就会有麻烦。比如nibbles: 0x1 0xa 0x2 0xb 0x3\ 组合成[]byte？ 0x1a 0x2b 0x30 还是 0x01 0xa2 0xb3可见无论怎么组合，都会有多写入一个无效的nibble。等再解析的时候，我们怎么知道哪个是无效的呢？另一个问题是，我们该如何解析快捷结点中的value所代表的数据。它是代表真正的value数据，还是另一个结点？这两个问题存在的原因在于，Trie中的结点是需要进行数据库存取的。如果只是在内存中，这两个问题不会存在：只在内存中没有必要把nibble组成的key变成[]byte类型；通过数据的结构体类型也很容易知道value所代表的数据类型。但要将快捷结点存入数据库中，需要将nibble组成的key变成[]byte存储（其实也可以直接存储nibble数组，只是多占了一倍空间）；而从数据库中读取value所代表的数据时，需…