一个下一代智能合约和去中心化应用平台.pdf
一个下一代智能合约和去中心化应用平台 作者 eLink 在 2009 年的时候, 中本聪的比特币 , 经常被认为是一个在金融和货币领域里比较激进的做法,它作为世界上第一个数字货币,它既没有强大的背景支持,也没有所谓的 “ 内在价值 ” ,更没有集中的发行人或控制者, 更有甚者, 人们 都不知道中本聪 本 人是谁 o╯□╰o 。然而,另一方面, 一个 可以说是更加重要的一面,比特币的底层的区块链技术作为一个去中心化的一致性的基础技术,受到越来越多的技术专家的注意。现在有很多采用区块链技术的山寨比特币,如用区块链 上的数字来代表客户的资产和金融工具的彩色币 “colored coins” , 注册登记姓名用的 姓名币 “ Namecoin” ,以及更加复杂的应用 ,包括让数字资产直接被一 段可以执行任意规则的代码来控制的智能合约 “smart contracts” ,甚至是基于区块链的 “ 去中心化的自治组织( decentralized autonomous organizations) ” DAOs 。以太坊所尝试的是提供一个区块链,它内置了一个完全成熟的图灵完备的程序语言,可以用这个语言来创建 “ 合约 ” ,创建以上所说的任何的系统, 还有许多我们还没有想到的,只要简单的使用几行代码就可以构建起 来 。 以太坊 其实 是一个可编程的区块链,它不仅仅是给用户提供了一些预定义操作(如比特币他只能交易),以太坊允 许用户创建属于他们自己的任意复杂的操作。以太坊作为一个平台为去中心化 的不同的区块链应用提供服务。 目录 比特币和现有概念的介绍 o 历史 o 比特币一个状态转移系统 o 挖矿 o 梅克尔树( Merkle Trees) o 山寨区块链应用 o 脚本 ( Scripting) 以太坊 o 以太坊账户 o 信息和交易 o 以太坊状态转移函数 o 代码执行 o 区块链和挖矿 应用 比特币和现有概念的介绍 历史 去中心化的货币的概念,和上面所说的备选的应用像产权登记等已经存在了几十年。上世纪 80年代和 90 年代的匿名电子现金协议主要使用了一种被称为 “ 乔姆盲签( Chaumian Blinding) ” 的加密技术,这种技术为这些新货币提供了很高的隐私保护,但是由于他们的基础协议在很大程序上需要依赖于一个中央中介,因此未能获得支持。 1998年,戴伟( Wei Dai)的 b-money 首次引入了通过解决计算难题和去中心 化的共识来创造货币的思想,但是该建议并未给出实现去中心化的共识的具体方法。 2005年,芬尼( Hal Finney)引入了 “ 可重复的工作证明 ” ( reusable proofs of work)概念,它同时使用 b-money 的思想和 Adam Back 提出的计算困难的哈希现金( Hashcash)难题来创造密码学货币。但是,这种概念再次迷失于理想化,因为它需要可信任的计算作为后端。在2009年,一种去中心化的货币由中本聪在实践中首次得到实现,通过使用公共密钥密码来管理所有权,并通过一种一致性算法来跟踪货币的持有者, 这种算法被称为 “ 工作证明 ” 。这 “ 工作证明 ” 的算法是一种突破,因为它同时解决了 2个问题。首先,它提供了一种简单的、有节制的有效的共识算法,允许网络中的节点一起同意比特币总帐状态的一组更新。其次,它提供了一种机制,允许任何节点自由进入共识的处理进程,从而解决了谁来影响共识的政治难题,同时阻止 女巫攻击 。 这参与共识投票的节点的投票权比重是直接和节点它们自己的算力挂钩的。 从那时起, 一个新的方案被提出,称之为 “ 权益证明 ” ,计算一个节点的权重,与它所拥有的货币占比成 比例,而不是计算资源。关于这两种方法的相对优缺点的讨论超出了本 课程 的范围,但是应该 知道 的是,这两种方法都可以作为加密货币的支柱。 比特币一个状态转移系统 从技术角度来说 , 这加密货币的账本,如比特币可以被看作为一个状态转移的系统 , 在这个系统里 , 有一个包含 了 现在所有已存在的比特币的持有者的状态,并且有一个 “ 状态转移函数 ” 可以使用一个状态和一个交易来产生一个新的状态。在一个标准的银行体系里 , 这状态 就 是一个资产负债表 , 当一个交易要求把 X的钱,从 A转移到 B时, 那么它的状态转移函数就会从 A的账户中减去数量为 X的金额,然后在 B的账户中增加数量为 X的金额。如果 A的账户中没有 X 的钱,那么状态转移函数就会返回一个错误。所以,我们可以做如下定义 //使用一个状态和一个交易才生一个新状态,或者返回错误 APPLYS,TX - S or ERROR 在银行 系统中,它可以定义成这样 APPLY{ Alice 50, Bob 50 },“send 20 from Alice to Bob“ { Alice 30, Bob 70 } 或者 APPLY{ Alice 50, Bob 50 },“send 70 from Alice to Bob“ ERROR 这 “ 状态 ” 在比特币中是指所有的已经被挖出的但是还没消费的硬币的集合 技术上 , “ 没有被花掉的交易的产出 unspent transaction outputs” 或 UTXO ,每个 UTXO都有一个面值和一个持有者 持有者是由 20个字节组成的地址,其本质是一个加密的公钥 . 一个交易包含了一个或多个输入,每一个输入都包含了对一个已存在的 UTXO的引用,和用持有者的地址所关联着的私钥来产生的一个加密签名 , 并且会产生一个或多个输出 , 每一个输出包含一个用于添加到状态的新的 UTXO。 这状态转移函数 APPLYS,TX - S 可以被大概的定义如下 1. 在 TX中的每个输入 o 如果被引用的 UTXO 不在 S里,返回一个错误 . o 如果提供的签名和 UTXO的所有者匹配不上 , 返回一个错误 . 2. 如果所有的输入的 UTXO 的面值的和少于所有输出的 UTXO的面值的和,返回一个错误 . 3. 返回一个所有输入的 UTXO 都被移除的,所有输出的 UTXO都被加进的新的 S . 第一个步骤的前半部分防止交易的发送方消费不存在的硬币 , 第一步骤的后半部分阻止了交易的发送方使用别人的硬币 , 第二个步骤是强制的价值保护。为了使用这种支付方式,协议如下。 假设 Alice 想发送 11.7 BTC 给 Bob. 首先 , Alice 要找到一组她自己拥有的有效的 UTXO ,且总数要至少不低于 11.7 BTC. 实际上 , Alice 不会恰巧刚好拥有 11.7 BTC; 她得到的最小值是 64212,她然后使用这 3个输入和 2个输出创建了一个交易。 这第一个输出是 11.7 BTC ,是输出 Bob,第二个输出是剩下的 0.3 BTC “ 找零 ” 。如果 Alice 没有要求把这个找零发送到她自己的账户上 , 那么这矿工可以要求拥有这个零钱 . 挖矿 如果我们有一个可信任的中央服务器 , 那么实现这个系统是一件很简单的事情 ; 就按照需求所描述的去编写代码即可,把状态记录在中央服务器的硬盘上。 然而,与比特币一样,我们试图去建立一个去中心化的货币系统 , 所以,我们需要把状态转移系统和一致性系统结合起来,以确保每个人都同意这交易的顺序。比特币的去中心化的一致性处理进程要求网络中的节点连续不断的去尝试对交易进行打包,这些被打成的包就称为 “ 区块 ” 。 这个网络会故意的每隔 10分钟左右就创建一个区块 , 每一个区块里都包含一个时间戳,一个随机数,一个对上一个区块的引用 ,和从上一个区块开始的所有交易的列表。随着时间的推移,这会创建一个持久的,不断增长的区块链,这个区块链不断的被更新,使其始终代表着最新的比特币总账的状态。 在这个范例中,用来验证一个区块是否有效的算法如下 1. 检查其引用的上一个区块是否存在并且有效 . 2. 检查这个区块的时间戳是否大于上一个区块的时间戳 并且小于 2小时之内 3. 检查这区块上的工作证明是否有效 . 4. 让 S[0] 成为上一个区块的最末端的状态 . 5. 假设 TX 是这个区块的交易列表,且有 n 个交易。 做 for循环,把 i 从 0加到到 n-1, 设置 S[i1] APPLYS[i],TX[i] 如果任何一个 应用 APPLY返回错误,则退出并且返回。 6. 返回 true,并且把 S[n] 设置 成这个区块最末端的状态。 从本质上说,区块中的每一个交易都必须提供一个有效的状态,从交易执行前的标准状态到执行后的一个新的状态。 注意,状态并没有以任何方式编码进区块中 ;它纯粹是一个被验证节点所记住的抽象,并且它只能用来被从创世区块起的每一个区块进行安全的计算,然后按照顺序的应用在每一个区块中的每一次交易中。此外,请注意矿工把交易打包进区块的顺序是很重要的 ; 如果一个区块中有 2 个交易 A和 B,B花了一个由 A创建的 UTXO, 那么如果 A比 B更早的进入区块,那么这个区块将是有效的,不然就是无效的。 在上述列出的验证条件中, “ 工作证明 ” 这一明确的条件就是每一个区块的 2 次 SHA256 哈希值 , 它作为一个 256位的数字 ,必须小于一个动态调整的目标值 , 截止到本文写作的时间,该动态调整的值的大小大约是 2的 187次方 。 这样做的目的是为了让创建区块的算法变难 , 从而,阻止幽灵攻击者从对它们有利的角度出来,来对区块链进行整个的改造。因为 SHA256 被设计成一个完全不可预测的伪随机函数 , 这 创建一个有效区块的唯一的方法只有是不断的尝试和出错, 不断对随机数进行递增,然后查看新的哈希值是否匹配。 按照当前的目标值 2的 187次方,这个网络在找到一个有效的区块前,必须进行 2的 69次方次的尝试 ; 一般来说 ,每隔 2016个区块,这个目标值就会被网络调整一次 ,因此网络中平均每隔 10分钟就会有一些节点产生出一个新的区块。为了补偿这些矿工的计算工作 , 每一个区块的矿工有权要求包含一笔发给他们自己的 12.5BTC(不知道从哪来的)的交易。另外 ,如果任何交易,它的总的输入的面值比总的输出要高,这一差额会作为 “ 交易费用 ” 转给矿工。顺便提一下,对矿工的奖励是比特币发行的唯一途径,创世状态中并没有比特币。 为了更好的理解挖矿的目的 ,让我们来检测一下,当恶意攻击发生时会发生什么 . 由于比特币的底层的加密技术众所周知是安全的 ,所以这攻击者的目标将是比特币系统中的某个部份,那就是没有被密码直接保护的交易的次序。攻击者的策略 其实 很简单 1. 发送 100 BTC 到一个商人 ,以兑换一些商品 最好是快速交易的数字商品 2. 等待商品的发货 3. 创建另一个交易,发送同样的 100 BTC 给自己 4. 尝试让网络相信他发给他自己的那个交易是最新出现的。 一旦步骤 1发生 , 几分钟后,一些矿工就会把这个交易打包进一个区块 , 假设 声明该区块编号是 270000. 大约一个小时后 , 在那个区块之后又会有新增的五个区块添加到区块链中 , 这五个区块都间接的指向了那个交易,从而 “ 确认 ” 了 那交易是真的 。在这一刻,商家接收到了货款,并且发出了商品 ; 因为我们假设是一个数字商品,所以攻击者能立刻就收到货。 现在攻击者创建另一个交易,向他自己 的另一个账户 发送这 100 BTC 。如果这个攻击者只是简单的释放了这个交易,那么这个交易将不会被执行 ; 矿工将会尝试运行 APPLYS,TX ,注意那个 TX 消耗一个在以太坊状态中已经不存在的 UTXO。因此,这个攻击者创建了一个比特币区块链的 “ 分支 ” , 开始挖取区块 270000的另一个版本,这个版本指向同样的区块 269999作为一个父亲 ,但是用这新的交易替换了旧的。因为这区块的数据是不同的 , 这就需要为相关的区块重新做工作证明。 此外 ,这个攻击者的新的版本的区块 270000有一个不同的哈希,所以这已存在的区块 270001 到 270005 不会指向它 ; 因此 , 这原来的链和这攻击者的新链是完全独立的。区块链的规则是在分支中最长的区块链链将会变成真正的链,所以合法的矿工将会继续在 270005这条链上工作,同时攻击者自己一个人单独的工作在新版本的 270000这条链上。为了让攻击者他自己的区块成为最长,他需要的计算能力比其他网络的总和还要多( “51 攻击 ” )。比特币的区块依赖之前所有区块的哈希。一个拥有巨大计算能力的攻击者可以重新设计工作的证明 PoW,并最终获得大量 的比特币。 默克尔树 Merkle Trees 01 在默克尔树中只要提供少数的几个节点就可以给出一个分支有效性的证明 02 试图改变默克尔树的任一部分都将会导致链条上在某处发生不一致的情况 比特币的一个重要特性,这区块是存在一个多级数据结构中的 。一个区块的 “ 哈希值 ” 实际上只是这个区块的头信息的哈希值,一个大约 200个字节的数据,其中包含了时间戳,随机数,上一个区块的哈希和一个存储了这个区块中所有交易的称之为默克尔树的数据结构的根哈希。 默克尔树是一种二叉树,包含了一组节点,它们的含有基础信息的树根有大量的叶子节点 ,一组中间节点,每一个节点都是它的 2个子节点的哈希,然后,最终的一个根节点,也是由它的 2 个子节点的哈希形成,代表着这树的 “ 顶端 ” 。 这个默克尔树的目的是允许在一个区块中的数据能够被零散的传递 一个节点只能从一个源来下载一个区块的头信息, 树的一小部分关联着另一个源 ,并且任然可以保证所有的数据都是正确的。之所以这样做行得通,是因为哈希值都是向上传导的 如果一个恶意的用户试图在默克尔树的底部替换一个假的交易 , 这个更改将导致上面的节点发生变化,然后上面的节点的变化又会导致上上面的节点发生变化,最终改变这个数根节点,因此也改变了这区块的哈希,导致这个协议把它注册成一个完全不同的区块 几乎可以肯定是一个无效的工作证明 . 这默克尔树协议对比特币的长期可持续发展是必不可少的。比特币网络中的一个 “ 完整节点 ” , 截止到 2014 年,占用了大约 15G 的磁盘空间,并且每月正在以 10亿字节的速度递增。目前,这对于电脑来说是没有问题的,但是在手机上却是不现实的。在以后的将来,只有商业的和业余爱好者才能参与玩比特币。一个称之为 “ 简化支付验证( simplified payment verification) ” SPV 的协议 允许另一种类型的节点存在,这种节点称之为 “ 轻节点( light nodes) ”, 其下载区块的头信息 ,在这区块头信息上验证工作证明,然后只下载与之交易相关的 “ 分支 ” 。 这使得轻节点只要下载整个区块链的一小部分,就可以安全地确定任何一笔 比特币交易的状态和账户的当前余额。 山寨区块链应用 将底层的区块链理念应用到其他概念上的想法也有很长的历史了。在 2005年 , 尼克萨博提出了这个概念 “ 用所有权保护产权 ( secure property titles with owner authority) ”, 文档描述了 “ 复制数据库的新技术 ” 将如何使用一个基于区块链的系统来存储谁拥有土地的注册登记信息, 建立一个精心设计的框架,包括 “ 宅地 ” , “ 逆权侵占 ” 和 “ 地税 ” 等概念。然而,不幸的是,那个时候 没有 一个 有效的复制数据库信息,因此,协议从未付诸实践。然而,在 2009 年之后,比特币的去中心化 的共识一被开发出来,许多山寨应用就迅速涌现出来。 Namecoin – 创建于 2010 年,名字币是一个去中心化的名字注册数据库 。 在去中心化的协议中,像 Tor, Bitcoin 和 BitMessage, 这些需要有一些识别账号的方法,这样用户就可以和其他人进行交互了,但是现存在的所有的解决方案中,这个标识符都是一个伪随机的哈希字符串像 1LW79wp5ZBqaHW1jL5TCiBCrhQYtHagUWy。在理想情况下,人们一般都希望拥有一个像 “george” 这样的名字。然而,问题是如果一个用户可以创建 一个名为 “george” 的账号的话, 那么其他人也可以使用相同的过程来为自己注册一个名为 “george” 的账号,并且冒充他们。唯一的解决方案只能是先申请原则,第一个人可以注册成功,其他人都注册失败 – 这是 一个完全适用于比特币的 共识协议的 解决方案 。域名币是利用区块链实现名称注册系统的最早的、最成功的系统。 Colored coins – 彩色币的目的是为人们在比特币区块链上创建自己的数字货币,或者, 其他 一般意义上的货币 – 数字令牌提供服务。依照彩色币协议,人们可以通过为某一特别的比特币 UTXO指定 颜色,发行新的货币。该协议递归地将其它 UTXO定义为与交易输入 UTXO相同的颜色。这就允许用户保持只包含某一特定颜色的 UTXO,发送这些 UTXO 就像发送普通的比特币一样, 但是需要 通过回溯全部的区块链判断收到的 UTXO颜色。 Metacoins – 元币的理念是在比特币区块链上创建新的协议,利用比特币的交易保存元币的交易,但是采用了不同的状态转换函数 APPLY’ 。因为元币协议不能阻止比特币区块链上的无效的元币交易,所以增加一个规则如果 APPLY’S,TX 返回错误,这一协议将默认APPLY’S,TX S。这为创建任意的、先进的不能在比特币系统中实现的密码学货币协议提供了一个简单的解决方法,而且开发成本非常低,因为挖矿和网络的问题已经由比特币协议处理好了。 因此,总得来说,有 2中构建共识的方法 一是 构建一个独立的网络, 二是 在比特币之上建立一个协议。 前一种方法,在名字币这样的应用中相当的成功,但很难实现;每一个独立的实现都需要启动一个独立的区块链,以及构建和测试所有必要的状态转移 函数 和网络代码。此外 ,我们预测去中心化技术的应用会以指数级别的速度增长,绝大多数的应用会因为太小,而不能保护好它们自己的区块链 ,另外,我们还注意到存在大量去中心化的应用程序 ,特别是去中心化的自治组织 ,它们需要相互作用。 基于比特币的方法,有一个缺陷,它没有继承比特币的简化支付验证( SPV)的功能。 SPV 可以让比特币使用区块链的深度来做验证;在某种程度上,一旦一个交易 已经离的足够远了,就可以放心地说, 这个交易 就是合法的状态的一部分。基于区块链的元协议,从另一方面说,不能强制区块链不包含用它们自己的协议验证无效的交易。因此,一个完全安全的 SPV 元协议的实现需要从比特币区块链的末端一直扫描到顶端,这样才能确定某些交易的合法性。 目前,基于比特币的元协议的所有 “ 轻 ” 应用的实现都依赖于一个受信任的服务器来提供数据,这可以说是一个非常不理想的,尤其是当一个加密货币的需要消除信任的时候。 脚本 即便是没有任何扩展,这比特币的协议实际上确实促进了一个弱化版的 “ 智能合约 ” 的概念。 UTXO 在比特币中不是只被一个公钥持有 , 而是还被在一个基于堆栈的程序语言组成的复杂的脚本所持有着。 在这个范例中,一个交易消耗的 UTXO必须提供满足脚 本的数据。实际上,这最基本的公钥所有权机制也是通过一个脚本来实现的这个脚本使用一个椭圆曲线签名作为一个输入,验证拥有这个 UTXO 的交易和地址,如果验证成功,则返回 1,不然则返回 0。其他,更加复杂的脚本存在于各种复杂的用例中。 例如,你可以构造一个脚本,它要求从给定的三个私钥中,至少要选其中的 2个来做签名验证( “ 多重签名 ” ),这个对公司账本,储蓄账户等来说非常有用。脚本也能用来对解决计算问题的用户支付报酬。人们甚至可以创建这样的脚本 “ 如果你能够提供你已经发送一定数额的的狗币给我的简化确认支付证明,这一比特币 就是你的了 ” ,本质上,比特币系统允许不同的密码学货币进行去中心化的兑换。 然而,在比特币中 的 脚本语言有几个重要的限制 缺乏图灵 -完备 – 那就是说,虽然比特币脚本语言支持的计算方式很多,但是它不是所有的都支持。在主要类别中缺失循环。 它 这样做的目的是为了防止对交易的验证出现死循环;理论上,它的脚本是可以克服这个障碍的,因为任何的循环都可以通过 if 语句重复多次底层代码来模拟,但是这样的脚本运行效率非常低下。 值的盲区 – 一个 UTXO 脚本没有办法提供资金的颗粒度可控的出金操作。比如 , 一个预言合约( oracle contract )的其中一个强大的用例就是一个套期保值的合约, A和 B都把价值1000的 BTC放到合约中, 30天后,这个合约把价值 1000的 BTC发给了 A,剩下的发给了B。 这就需要合约要确定 1BTC以美元计值多少钱。然而,因为 UTXO是不可分割的,为实现此合约,唯一的方法是非常低效地采用许多有不同面值的 UTXO(例如有 2k的 UTXO,其中 K可以最大到 30并使预言合约挑出正确的 UTXO发送给 A和 B。 状态缺失 – UTXO 要么被使用了,要么没有被使用;这会使得多阶段的合约和脚本没有机会保持任 何其他的内部状态。这使得制作多阶段的期权合约、去中心化的交换协议或两阶段加密承诺协议变得困难 对于安全计算奖金来说是必要的 。这也意味着, UTXO只能用于构建简单的、一次性的合约,而不是更复杂的 “ 有状态 ” 的合约,比如去中心化的组织,并且使得元协议难以实现。 区块链盲区 -UTXO对某些区块链数据视而不见,比如随机数和之前的区块的哈希。这严重限制了博彩和其他一些类别的应用,因为它剥夺了一种潜在的有价值的脚本语言 随机数 也就是在比特币的脚本中是没有随机数的。 因此,我们看到了在加密货币之上构建高级应用程序的三 种方法 一, 构建一个新的区块链, 二,在比特币之上使用脚本, 三, 在比特币之上构建一个元协议。 构建一个新的区块链可以无限制扩展功能集,但是这样做非常消耗时间。使用脚本很容易实现和标准化,但在其功能上非常有限,而元协议虽然容易,但在可伸缩性方面却存在缺陷。在以太坊中,我们打算建立一个替代性的框架,它提供了更大的开发和更强大的轻客户属性,同时允许应用程序共享一个经济环境和区块链安全。 以太坊 以太坊的目的是创建一种去中心化应用的协议,提供一套对大量的去中心化应用程序非常有用的新方案,特别强调快速开发,对小的和少数人使用的应用也非常安全(小而使用人少的应用容易被51攻破),以及不同的应用程序之间能够有效的互动。以太坊通过建立在本质上是抽象的基础层来完成这一工作一个区块链其内置了图灵完备的编程语言,允许任何人编写智能合约和去中心化的应用程序,在这些应用程序中,他们可以创建任意的属于他们自己的规则、交易格式和状态转换函数。名字币的一个简单版本 在以太坊 可以用两行代码来编写完成,而其他协议如货币和信用 系统则可以用不到 20行的代码来构建。智能合约 -包含价值而且只有满足某些条件才能打开的加密箱子 -也能在我们的平台上构建,并且因为图灵完备性、价值知晓( value-awareness)、区块链知晓( blockchain-awareness)和多状态所增加的力量,远比特币脚本所能提供的 功能 强大得多。 以太坊虚拟机 以太坊是一个可编程的区块链,不仅仅是给用户一些预定义操作(如比特币只交易),以太坊允许用户创建属于他们自己的复杂的操作。以太坊作为一个平台为不同的区块链应用提供服务。 狭义来说,以太坊是一系列协议,其核 心就是一个以太坊虚拟机,能执行遵守协议的任何复杂的代码。以太坊虚拟机是图灵完备的,开发者可以在虚拟机上使用像 javascript, python这样的友好的编程语言来创建应用。 和任何的区块链一样,以太坊包含了一个点对点的网络协议。这以太坊区块链是被链接着这个网络的各个节点维护和更新的。网络中的各个节点的虚拟机都执行相同的指令来共同维护区块数据库,因为这个原因,以太坊有时候被人称为 “ 世界计算机 ” 。 以太坊全网的大规模并行计算不是只为了提计算效率,而是为了保证全网的数据一致性。实际上,这使得在以太网上的 运算要 比传统的电脑慢的多,成本也昂贵得多。全网中的每一台虚拟机的运行都是为确保全网数据库的一致性。去中心化的一致性给全网极端的容错能力 ;抗审查能力和永不宕机能力等 以太坊账户 以太坊的基本单元是账号。 每一个账户都有一个 20个字节长度的地址 。 以太坊区块链跟踪每一个账号的状态,区块链上所有状态的转移都是账户之间的 令牌 (令牌即以太币)和信息的转移。以太坊有 2 种账户类型 外部账号,简称 EOA,是由私钥来控制的。 合约帐户 ,由合约代码来控制 ,且只能由一个 EOA账号来 操作 对于大多数用户来说 , 最基本的区别在于,用户掌握着 EOA账号,因为用户掌握着控制 EOA账号的私钥。而合约账号由内部程序代码来控制的,当然掌控私钥的 EOA账户可以通过编写特定的程序代码来掌控合约账户。流行的术语 “ 智能合约 ” 就是合约账号中的代码,当一个交易被发送到该账户时,合约中的代码就会被执行。用户可以通过把代码部署到区块链中来创建一个新合约 ,也即创建了一个新的合约账户 。 合约账户只有在 EOA账户发出一个指令的时 候才会去执行一个操作。所以一个合约账户是不可能自己去执行一个操作的,如生产一个随机数或执行一个 API 调用等,它只有在 EOA 账户作出确认的情况下才会去做这些事情。这是因为以太坊要求节点能够对计算的结果无论对错都达成一致,这就对操作有了一个必定会执行的要求。 在以太坊中, 全网的 状态是由被 “ 账户 ” 的对象组成的,账户之间可以直接的进行价值和信息的转移,一个以太坊的账户包含下面 4个字段 随机数 , 一个计数器,用以确保每个交易都只会被处理一次 账户当前的 以太币额度 账户的 合约代码 , 如果有的话 这个账户的 存储 默认空 “ 以太币 ” 是以太坊主要的内部加密燃料,并且被用来支付交易的费用。一般情况下,有 2种类型的账户 外部拥有的账户 ,被私钥控制的,和 合约账户 , 被合约代码控制的。外部拥有的账户没有代码,用户可以通过一个外部账户来创建和签名一个交易来送一个消息;合约账户中,每次当这个合约收到一个消息的时候,它的代码就会被激活,允许它读取这个消息,并且写入到内部存储中,然后按照一定顺序发送其他的消息或创建合约等。 消息和交易 名词 “ 交易 ” 在以太坊中是指签名的数据包,这个数据包中存储了从外部账户发送的消息,交易包含以下内容 消息的接收者 一个可以识别发送者的签名 发送方给接收方的以太币的数量 一个可选的数据字段 一个 STARTGAS 值 , 表示执行这个交易允许消耗的最大计算步骤 一个 GASPRICE 值 , 表示发送方的每个计算步骤的费用 前面三个是每一个加密货币都有的标准字段。默认情况下第四个数据字段没有任何功能,但是合约可以访问这里的数据;举个例子,如果一个合约是在一个区块链上提供域名注册服务的,那么它就会想把这数据字段中的数据解析成 2个字段,第一个字段是域名,第二个字段是域名对应的 IP地址。这个合约会从数据字段中读取这些值,然后适当 把它们保存下来 。 这个 STARTGAS 和 GASPRICE 字段 是以太坊的 预防 拒绝式攻击用的,非常重要。为了防止在代码中出现意外或敌对的无限循环或其他计算浪费,每个交易都需要设置一个限制,以限制它的计算 总步骤是一个明确的值。这计算的基本单位是 “ 汽油( gas) ” ; 通常,一个计算成本是一个 1 滴汽油,但是一些操作需要 消耗更多的汽油,因为它们的计算成本更高。在交易数据中每一个字节 需要消耗 5 滴汽油。这样做的目的是为了让攻击者为他们所消耗的每一种资源,包括计算,带宽和存储支付费用;所以消耗网络资源越多,则交易成本就越大。 消息 合约有能力向其他合约发生 “ 消息 ” 。消息是虚拟的对象,它从来不会 被 序列 化 ,而且只存在于以太坊的执行环境中。一个消息包含以下内容 消息的发送者 隐式 消息的接收者 与消息一起传送的以太币的数量 一个可选的数据字段 一个 STARTGAS 值 从本质上说 ,一个消息就像一个交易 , 只是它是由一个合约产生的而不是一个外部用户。一个正在执行代码的合约,当执行到 CALL 代码时,会产生并执行一个消息。就像一个交易,一个消息会导致接收方的账户运行它的代码。因此,合约之间 是 可以互相发生 作用的 。 以太坊状态转移函数 以太坊的状态转移函数 APPLYS,TX - S 可以被定义成下面的 1. 检查这个交易是不是合法的 ,签名是不是合法的 , 这随机数是不是匹配这个发送者的账户,如果答案是否定的,那返回错误。 2. 用 STARTGAS * GASPRICE 计算交易的费用,并且从签名中确定这个发送者的地址。 从发送者的余额中减去费用,并且增加发送者的随机值。如果余额不够,则返回错误。 3. 初始化 GAS STARTGAS, 并根据 这交易中的字节数拿走一定量的汽油。 4. 把交易的值从发送的账户转移到接收者的账户。如果接收者的账户还不存在,就创建一个。如果这个接收者的账户是一个合约,那么就运行合约的代码直到完成,或者报汽油消耗光的异常。 5. 如果值转移失败了,因为发送者没有足够多的余额,或代码执行消耗光了汽油,恢复除了支付的费用外的所有的状态,并且把这个费用添加到矿工的账户上。 6. 另外 ,把所有剩下的汽油 退还给发送者,然后把用于支付费用的汽油发送给矿工。 举例,假设合约的代码是这样的 if self.storage[calldataload0] self.storage[calldataload0] calldataload32 注意,真实的合约代码是用底层的 EVM代码编写的;这个列子是用一个叫 Serpent 的高级语言写的。假设这个合约的存储开始是空的,并且发送了一个交易,其中包含 10个以太币, 2000个汽油,汽油价格是 0.001比特币,和 64字节的数据,其中 0-31字节代表数字 2,32-63字节代表字符串 CHARLIE。在这个案例中,这状态转移函数的处理如下 1. 检查者交易是否有效并且格式完好。 2. 检查者交易的发送 者是否至少有 2000 * 0.001 2 以太币。如果有,则从发送者的账户中减去 2以太币。 3. 初始化 汽油( gas) 2000;假设这个交易是 170 个字节长度并且每个字节的费用是 5,那么减去 850,汽油还剩 1150。 4. 从发送者的账户减去 10 个以太币,并且添加到合约的账户中。 5. 运行合约的代码 . 在这里例子中 检查合约的存储的第 2个索引是否已经被使用,注意到它没有,然后就把这 数据 存储的第二个索引的值设置为 CHARLIE. 假设这个操作消耗了 187个汽油,那么剩下的汽油总量是 1150 – 187 963 6. 把 963 * 0.001 0.963 以太币加到发送者的账户,然后反正结果状态。 如果交易的接收端没有合约,那么这总的交易费用就简单的等于汽油的价格乘以这个交易的字节长度,与交易一起发送的数据字段的数据将无关重要。 注意,在恢复这个方面,消息和交易的处理方式是相同的 如果一个消息执行消耗光了汽油,那么这消息的执行和其他被触发的执行都会被恢复,但是父类的执行不 会 恢复。 代 码执行 以太坊的合约代码是用底层的基于堆栈的字节码语言来编写的,被称为 “ 以太坊虚拟机代码 ” or “EVM 代码 ” 。这代码有一系列的字节组成,其中每一个字节都标识一个操作。在一般情况下 ,代码的执行是一个无限循环,直到代码运行结束或遇到错误,或检测到 STOP 或 RETURN 指令。这些操作有三种类型的空间可用于存储数据 堆栈 , 一种后进先出的容器 内存 , 一种无线扩展的字节数组 合约的持久化 存储 , 一种键值对的方式 . 不像堆栈和内存 ,计算结束后将会被重置 , 存储将长期保存。 代码还可以访问值(以太币),发送者,传入的消息的数据,以及区块的头信息,并且也可以返回一组字节数组当做输出。 区块链和挖矿 这以太坊的区块链和比特币的区块链有很多相似的地方,也有很多不同的地方。这个以太坊和比特币在区块链体系中最重要的不同点是 以太坊的区块同时包含了交易列表和最近区块的状态。除此之外, 2个其他的值,区块的编号和难度值也存在在区块中。以太坊中最基本的区 块验证算法如下 1. 检查上一个区块是否存在和其有效性。 2. 检测这区块的时间戳,是不是比上一个区块的大,并且小于 15分钟 3. 检查这区块编号,难度值,交易根( transaction root) , 叔根( uncle root)和汽油限制是否有效 4. 检查这区块的工作证明是否有效 5. 把 S[0] 设置成上一个区块的末端的状态 6. 让 TX 成为这区块的交易列表,如果有 n 个交易。则做 for循环 For i in 0.n-1, 设置 S[i1] APPLYS[i],TX[i]. 如果任何一个应用发生错误,或这区块中 汽油的总的消耗达到了 GASLIMIT, 则返回一个错误 . 7. 让 S_FINAL 等于 S[n], 但是把支付给矿工的奖励添加到这区块里。 8. 检查这个状态 S_FINAL 的默克尔树树根是不是和区块头信息中所提供的状态根是一样的。如果是,则区块有效,不然则无效。 乍看上去,这种方法似乎效率很低,因为它需要将整个状态存储在每个块中,但在现实中,效率应该与比特币相当。原因在于,状态存储在树结构中,并且每个块后,只需要修改树的一小部分。此外,由于所有的状态信息都是最后一个区块的一部分,所以不需要存储整个区块链的历史 这一策略,如果它可以应用于比特币,那么它的磁盘空间将节省 5-20倍。 以太坊网络中 交易会被验证这网络的节点收集起来。这些 “ 矿工 ” 在以太坊网络中收集、传播、验证和执行交易,然后整理归档这些交易,打包成一个区块,与别的矿工竞争将区块添加到区块链中,添加成功的矿工将收到奖励。通过这样的措施,鼓励人们为区块链全网提供更多的硬件和电力支持。 应用 以太坊框架本身并没有什么特别的功能。就好像 程序语言一样,它做什么,都是由企业或开发者自己来决定的。如,复杂的金融合约的自动化。比特币可以让用户不通过第三方机构,如银行,政府等就可以直接兑换货币。但是以太坊的介入可能会产生更加深远的影响,因为任何复杂的金融操作都是可以自动被执行的,并且可以写成代码在以太坊上运行。当然除了金融外,任何情况下,只要对信用、安全、和持久有极高的要求,比如资产注册登记,投票,管理和物联网等都有可能受到以太坊平台的影响。 一般来说,在以太坊上有三种类型的应用。第一种是金融应用,这包括 子货币,金融衍生品,套期保值合约,和一些雇 佣合同等。第二类是半金融应用,这里有钱的存在但也有很重的非金钱的方面;最后,还有在线投票和去中心化治理这样的完全的非金融应用。 参考资料 以太坊官网网站 https//ethereum.org/ 区块链信息查看 https//etherchain.org 去中心化的应用 https// 以太坊白皮书原文 https//