精通以太坊Note

Mastering Ethereum

本书链接:https://github.com/oldnicke/MasteringEthereum

第一章 什么是以太坊

以太坊是一种确定性但实际无界的状态机,有两个基本功能:全局可访问的单例状态和对状态进行更改的虚拟机。
进一步说,以太坊是一个开源的、全球的去中心化计算架构,它执行被称为智能合约的程序,使用区块链来同步和存储系统的状态,使用称为ether的加密货币来计量和约束执行资源成本。

状态机
状态机是有限状态自动机的简称,是现实事物运行规则抽象而成的一个数学模型。
包含四大概念:状态、事件、动作、变换

区块链的组件

  1. 一个链接参与者,传播交易和包含已验证交易的区块的点对点网络(基于gossip协议)
  2. 状态机中实现的一系列共识规则
  3. 消息,以交易的形式表示
  4. 根据共识规则处理交易的状态机
  5. 分布式数据库,区块链,记录所有状态转移的日志
  6. 共识算法,通过强制参与者竞争并使用共识规则约束他们,来分散区块链的控制权
  7. 上述内容的开源软件实现

gossip
gossip就是一个并行的图广度优先遍历算法。假设A得到某些信息,更新了自身的信息,A需要将信息告诉B、C等,然后B、C告诉其他的D、E、F、G,一直遍历。如果节点B收到A的消息,发现自己早就知道这个消息就直接忽略,从而可以防止图重复遍历。和路由器使用的路由表同步算法类似,只不过路由器还会维护每个路径的cost。gossip常用于维护集群的拓扑结构(路由器也是),被redis、consul使用。

gas
以太坊无法预测合约是否会终止,于是通过gas来限制智能合约使用的资源。
每一条指令都以gas为单位的成本,如果实际计算所消耗的gas超过了gas limit,EVM将终止执行。
gas是以太坊用于允许图灵完备计算的机制

从区块链到DApps
以太坊从作为一种可用于各种用途的通用区块链开始,其愿景已经扩展为编程DApp到平台。
DApp代表着比智能合约更广阔的视角。
一个DApp至少是一个智能合约和一个web用户界面。
进一步说,DApp是一个基于开放的、去中心化的、点对点基础架构服务的web应用程序

此外,DApp还常常包括其他去中心化组件:
去中心化p2p存储协议和平台
去中心化p2p消息传递和平台

DApp常写作ÐApps,Ð是拉丁字母,读作 ETH

web3
目前web2
DApp的概念旨在将web引入web3,去中心化对等协议将进入web应用程序的方方面面

web3代表着web应用程序的新愿景和焦点:从集中拥有和管理的应用程序,到去中心化协议的应用程序。

Ethereum+web3js+JS库,会在浏览器中运行的js应用程序和以太坊区块链相连接。此外,web3.js库还提供了一个名为Swarm的P2P存储网络接口和一个成文Whisper的P2P消息传递服务。根据以上组件,开发人员可以使用完整的应用程序开发套件来构建web3 DApp。


第二章 以太坊基础

以太坊:ethereum
以太坊货币:以太:ether:Ξ

账户
外部所有账户(EOA):拥有私人密钥的账户,可以控制资金或对合约的访问
合约账户:合约账户由以太坊记录,由EVM执行的软件程序的逻辑拥有和控制


第三章 以太坊客户端

以太坊客户端主要有六种语言编写
Go:Geth
Rust:parity
C++:cpp-ethereum
Python:pyethereum
Scala:mantis
Java:harmony

轻量级客户端可连接现有网络,如自己的完整节点、公共区块链、公开或许可的测试网或本地私有区块链。
实际上常用轻量级客户端(metamask)在所有不同节点选项之间切换。
此外轻量级客户端常和钱包换用,轻量级客户端除了提供钱包的交易功能外还提供API。


第四章 以太坊测试网

mainnet&testnet


第五章 密钥和地址

密码学是以太坊技术基础
加密可以用来证明秘密的知识而不泄漏(数字签名),或验证数据的真实性(数字指纹)
加密不是以太坊的重要组成部分,因为起通信和交易数据没有加密也不需要加密

简介

在EOA中,以太的所有权通过数字密钥、以太坊地址和数字签名建立

  • 公钥+私钥(数字密钥)
    数字密钥并不储存在区块链上或在区块链上传输,而是储存在钱包这个简单的数据库中
    钱包中的数字密钥完全独立于以太坊协议,可以由钱包软件生成和控制而无需连接区块链或互联网
    数字密钥可以实现区块链的去中心化信任和控制、所有权的证明等
    ✨在以太坊的交易中需要包含有效的数字签名,该签名只能由私钥生成。因此得到了数字密钥就意味着成为了该地址的资金所有者
    ✨数字密钥成对,为公钥和私钥。公钥类似账号,私钥类似密码。私钥大部分时候在钱包内保存。在交易付款中,收款人由以太坊地址表示,这往往代表公钥。但也并非所有的以太坊地址都代表公钥,也可以代表合同。
    ✨公钥从私钥中派生而来,公钥用于接收资金,私钥用于创建数字签名来签署交易以及支付资金。数字签名可用于验证合同的所有者或者用户。
    ✨公钥密码系统的特点是,很容易在一个方向上计算,但很难在反方向上计算。因此数字密钥的安全性和签名的不可伪造得以保证。

数学部分

  • 以太坊公钥
    以太坊公钥是椭圆曲线上的点,是一组满足椭圆曲线方程的XY坐标
    简单来说,公钥是两个数字连接在了一起,这两个数字是从一次单向的计算中从私钥产生,但你不能从公钥中算出私钥

  • 详细说明
    公钥使用椭圆曲线乘法和私钥计算:K=k*G
    其中k是私钥,G是一个常数点,K的结果是公钥
    椭圆曲线乘法被密码学家称为一种单向函数

  • 一个椭圆曲线

image
它将被定义在素数阶上,但在数学上与实数阶的椭圆曲线相同
而以太坊和比特币使用的椭圆曲线加密算法都是secp256k1 曲线
曲线可视化:https://www.desmos.com/calculator/ialhd71we3?lang=zh-CN
函数为:y^2=x^3+7
它被定义在素数阶p上,p = 2^256 – 2^32 – 2^9 – 2^8 – 2^7 – 2^6 – 2^4 – 1
常数点G是椭圆曲线上一点,被称为基点,很大
参数n,是使得nG=0的最小正整数(此处0指无穷远点),具体值是n=2^256-43242048656565965685242086639498145599

  • 计算
    定义加法:
    P1、P2在椭圆曲线上,P3=P1+P2,P3也在椭圆曲线上。
    在几何上,连接P1、P2,与椭圆曲线相交于P3'=(x,y)。而P3=(x,-y)。
    image
    无穷远点:
    大致等于零点,常用(0,0)表示,虽然(0,0)不在椭圆曲线上
    P1、P2是同一个点,P1、P2的连线是切线;一些时候,切线垂直,此时的P3为无穷远点
    若P1是无穷远点,P1+P2=P2;此处看到无穷远点类似零点
    定义乘法:k*P=P+P+......+P

  • 生成公钥
    已知钱包生成了一个大整数k(为私钥)和一个椭圆曲线上的点生成点G(所有以太坊用户的生成点相同)
    则公钥K=k*G(相当于k次切线+反向,最后可以获得一个点)
    密码库(OpenSSL、libsecp256k1)可以帮助计算这个点K=(x,y)
    连接公钥的X和Y坐标:
    X-coordinate (32 bytes/64 hex) + Y coordinate (32 bytes/64 hex)
    因为以太坊使用的是未压缩的公钥,在前面加上04
    04+X-coordinate (32 bytes/64 hex) + Y coordinate (32 bytes/64 hex)
    即可的得到被序列化后的公钥

  • 计算以太坊地址
    计算以太坊地址使用的是未加04前的公钥
    用以太坊的哈希加密函数:Keccak-256 处理
    保留最后的20个字节(40位)(大端序中的最低有效字节)
    加上0x表示16进制
    即可得到以太坊地址

公钥:64字节 //046e145ccef1033dea239875dd00dfb4fee6e3348b84985c92f103444683bae07b83b5c38e5e2b0c8529d7fa3f64d46daa1ece2d9ac14cab9477d042c84c32ccd0
私钥:32字节 //f8f8a2f43c8376ccb0871305060d7b27b0554d2cc72bccf41b2705608452f315
地址:20字节 //0x001d3f1ef827552ae1114027bd3ecf1f086ba0f9

如何判断正在使用那种哈希加密函数(FIPS-202还是Keccak-256)
给一个预定输入,看输出判断
常用空输入
Keccak256("") = c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470
SHA3("") = a7ffc6f8bf1ed76651c14756a061d662f580ff4de43b49fa82d80a4b80f8434a

互换客户端地址协议(ICAP)为以太坊地址提供多功能、校验和互操作编码(钱包检测是否输入错误地址)
由于ICAP活名称服务器部署缓慢,现在只有几个钱包支持ICAP。
新标准以太坊改进建议55(EIP-55)
https://github.com/Ethereum/EIPs/blob/master/EIPS/eip-55.md

通过修改十六进制地址的大小写,EIP-55为以太坊地址提供了向后兼容的校验和
通过修改地址中字母字符的大小写,我们可以传达一个校验和,用来保护地址的完整性,防止输入或读取错误。如果钱包不支持EIP-55校验和,会忽略大写的事实。但如果钱包支持EIP-55校验和,就可以验证它并以99.986%的准确度检测错误。
原地址: 0x001d3f1ef827552ae1114027bd3ecf1f086ba0f9
EIP-55混合大小写校验和:0x001d3F1ef827552Ae1114027BD3ECF1f086bA0F9

EIP-55计算方式
简单来说先计算小写地址的哈希(不带0x)
如果哈希的相应数字大于等于0x8,则地址的字母要大写
Address: 001d3f1ef827552ae1114027bd3ecf1f086ba0f9 Hash :23a69c1653e4ebbb619b0b2cb8a9bad49892a8b9... EIP-55 : 001d3F1ef827552Ae1114027BD3ECF1f086bA0F9
输入地址的时候只要输错一位,计算出来的哈希就会发生变化,导致大小写的位置完全对不上


第六章 钱包

  • 钱包只包含密钥,代币记录在区块链中,用户通过钱包中的密钥签署交易来控制网络上的代币。

  • 目前有两种主要类型的钱包,通过他们包含的密钥是否彼此相关来区分
    一种是 非确定性钱包 JBOK,其中密钥是从随机数中独立生成的,密钥之间互不关联(不鼓励使用,麻烦,一般只有简单测试的时候用)
    一种是 确定性钱包 HD,所有密钥来自单个主密钥(成为seed)这种钱包中所有段密钥互相关联,只要seed还在就可以再次生成。确定性钱包使用了许多不同的密钥推导方法,最常用的是树状结构。
    HD钱包是管理许多密钥和地址的强大机制,并可以将他们与一系列英语单词相结合(助记词),更易于转录和跨钱包的导入导出。这个标准由BIP-39确定。

  • 助记词和脑钱包不同,区别在于脑钱包由用户选择单词,而助记次由钱包的随机性创建并呈现给用户

  • 种子512 bits(64位16进制)

  • 种子到助记词
    种子不是私钥,种子可以生成私钥。助记词即是钱包的备份。
    助记词是表示HD的种子的随机数的单词序列,从单词序列足以重建种子并派生所有的密钥。
    创建一个128到256位的随机序列(熵)。✨不同长度的随机序列,最后生成的助记词数量不同。
    通过取其SHA256哈希的第一部分(熵长度/32)来创建随机序列的校验和。
    将校验和添加到随机序列的末尾。
    将序列按照11bits划分。
    将每个11bits的值映射到预定义字典中的2048个词中的一个。
    助记词就是单词的序列。

  • 助记词到种子
    PBKDF2是一个密钥扩展函数,可以将熵导出成更长的种子,然后使用种子构建HD并生成密钥。
    密钥扩展函数有两个参数:助记词和salt
    PBKDF2密钥扩展函数的第一个参数是步骤6产生的助记词。
    PBKDF2密钥扩展函数的第二个参数是盐。盐由用户提供的密码字符串(在产生种子时指定,会改变助记词)和“mnemonic”组合起来。
    PBKDF2使用2048轮HMAC-SHA512哈希算法,扩展助记词和盐,生成512位的种子。

  • 128-bit entropy mnemonic code, with passphrase, resulting seed
    Entropy input (128 bits):0c1e24e5917779d297e14d45f14e1a1a
    Mnemonic (12 words):army van defense carry jealous true garbage claim echo media make crunch
    Passphrase:SuperDuperSecret
    Seed (512 bits):3b5df16df2157104cfdd22830162a5e170c0161653e3afe6c88defeefb0818c793dbb28ab3ab091897d0 715861dc8a18358f80b79d49acf64142ae57037d1d54

  • BIP-39标准允许在派生种子时使用可选的密码短语。如果没有使用密码短语,助记词将被一个由常量字符串"mnemonic" 组成的盐扩展,从任何给定的助记词中产生一个特定的512位种子。
    这里展示了生成助记词,种子和扩展私钥的独立网页。

  • HD钱包的一个特点是能从公开的父公钥派生子公钥

第七章 交易

交易是由EOA发起的签名消息,由以太坊网络传输并在以太坊区块链上记录。
它是唯一可以触发状态更改或者导致合约在EVM中执行的东西。
以太坊是一个全球的单实例状态机器,交易是唯一可以让状态机运动、改变状态的东西。即合约不会自动运行、以太坊不会自动运行,一切运行都始于交易

交易的基本结构
交易的网络序列化是交易结构的唯一通用标准
交易是一个序列化的二进制消息,其中包含以下数据:

  • nonce:由始发EOA(外部所有账户)发出的序列号,用于防止消息重播。
  • gas price:发起人愿意支付的gas价格(以wei为单位)。
  • start gas:发起人愿意支付的最大gas量。
  • to:目标以太坊地址。
  • value:发送到目标地址的ether数量。
  • data:变长二进制数据。
  • v,r,s:始发EOA的ECDSA签名的三个组成部分。
    交易消息不包含from字段,因为交易发起者的公钥可以从ECDSA签名中计算出来。

交易随机数nonce
这是交易中最重要也最少被理解的部分。
nonce:与此地址发送过的交易数量相等的标量值,或者,对于具有关联代码的帐户,表示此帐户创建的合约数量。
严格地说,nonce是始发地址的一个属性(它只在发送地址的上下文中有意义)。但是,该nonce并未作为账户状态的一部分显式存储在区块链中。相反,它是根据来源于此地址的已确认交易的数量动态计算的
nonce也可以被用于防止双花等。

跟踪nonce
查询账户已确认交易数量的最新计数
web3.eth.getTransactionCount("0x9e713963a92c02317a681b9bb3065a8249de124f") 40
最新计数为40,意味着下一个交易的nonce将是40。
nonce有着确认机制,意味着按照顺序创建多个交易后,其中有一个交易未被开采,那么后面等所有交易将被卡住。如果出现两个nonce相同的交易(并发时出错),前面的将进行,后面的会被拒绝。

并发、交易、nonce
在以太坊这种去中心化/分布式实时系统中,并发会突然出现。
简单来说,并发是多个独立系统同时计算,这些可以在相同的的程序中(多线程)、同样的CPU中(多进程)或不同的计算机中(分布式)。而以太坊是一个允许(节点、客户端、DApps)并发多系统,但强制实施单一状态。

交易gas
gasPrice & startPrice
gasPrice:每单位gas的汇率,1gas=?wei,1ether=10^18wei
startPrice:本次交易愿意付出的gas
gas是以太坊的燃料。gas不是ether,它是独立的虚拟货币,有相对于ether的汇率。gas与ether分离,以保护系统免受随着ether价值快速变化而产生的波动。

web3界面通过计算几个区块的中间价格来提供gasPrice建议
truffle(mainnet)> web3.eth.getGasPrice(console.log) truffle(mainnet)> null BigNumber { s: 1, e: 10, c: [ 10000000000 ] }

交易的接收者to
交易的接受人由to指定,包含一个20个字节的以太坊地址,可以说EOA或合约。
以太坊不会验证是否有这个地址,任何20个字节的值都是有效值。
验证地址是否有效,应该在用户界面层级完成。
如果发送到不存在的地址,ehter会燃烧。
实际上也存在着一些专门用于燃烧ether的合约。

交易的价值和数据
value&data
value和data可以都有,可以都没有,可以只有一个
只有value的交易是支付
只有data的交易是调用
没有value也没有data的交易是浪费gas

将value传给EOA或合约
对于EOA,将把发送的余额添加到地址的余额中。如果地址之前没有被观测过,会创建地址并初始化余额。
对于合约地址,会尝试调用data中指定的函数。如果没有data,EVM会调用目标合约的fallback函数,如果该函数是payable,将执行函数以确定下一步。
合约可以通过在调用付款功能时立刻抛出异常或由条件来拒绝收款。如果付款成功,合约状态将更新,ether余额增加。

将数据传到EOA或合约
一般如果交易包含data,大概率是发到合约上的。
如果发送到EOA上,多数钱包会忽视data
如果发送到合约上,data将被EVM认为是一个函数调用,调用指定的函数并将任何编码参数传递给该函数。
发送给合约的data是一个十六进制的编码
函数选择器:函数原型的Keccak256哈希的前4个字节。这使EVM能够明确地识别你希望调用的功能。
函数的参数:根据EVM定义的各种基本类型的规则进行编码。

✨交易中data格式的例子
在Faucet.sol中,我们为取款定义了一个函数:
function withdraw(uint withdraw_amount) public {
函数名称是withdraw,它只有一个参数是uint(它是uint256的别名)。所以withdraw的原型将是:
withdraw(uint256)
我们来计算这个字符串的Keccak256哈希值(我们可以使用truffle控制台或任何JavaScript web3控制台来做到这一点:多数情况下keccak256和sha3是同义词):
web3.sha3("withdraw(uint256)"); '0x2e1a7d4d13322e7b96f9a57413e1525c250fb7a9021cf91d1540d5b69f16a49f'
散列的前4个字节是 0x2e1a7d4d(一个字节是8位,表达0-255,代表两位十六进制)。
这是我们的“函数选择器”的值,它会告诉EVM我们想调用哪个函数。
接下来,让我们计算一个值作为参数 withdraw_amount 传递。我们要取款0.01 ether。我们将它编码为一个十六进制序列化的大端序无符号256位整数,以wei为单位:
withdraw_amount = web3.toWei(0.01, "ether"); '10000000000000000'
withdraw_amount_hex = web3.toHex(withdraw_amount); '0x2386f26fc10000'
现在,我们将函数选择器添加到这个参数上(填充为32字节):
2e1a7d4d000000000000000000000000000000000000000000000000002386f26fc10000
这就是我们的交易的 data,调用 withdraw 函数并请求0.01 ether作为 withdraw_amount。

特殊交易:注册合约
发送到零地址的,带有data但是没有value的交易,表示注册一个新的合约。
合约注册交易的to字段包括地址0x0,该地址不代表EOA,也不代表合约,不会花费ether和启动交易,仅作为注册合约的目的。

特殊交易:燃烧
燃烧地址
0x000000000000000000000000000000000000dEaD

数字签名
数字签名是用于证明数字信息或文件真实性的数学方案。有效的数字签名使得收件人有理由相信该信息是由已知的发件人创建的,发件人不能否认已发送信息,信息在传输过程中未被更改。(认证+不可否认+完整)
此处讨论数字签名如何工作,以及如何在不泄露私钥的情况下提供私钥所有权的证明。
椭圆曲线数字签名算法(ECDSA)
ECDSA是用于基于椭圆曲线私钥/公钥对的数字签名的算法。
数字签名在以太坊中的用途
签名证明私钥的所有者
授权的证明是不可否认的
签名证明交易数据在交易签名后不被修改
(认证+不可否认+完整)

数字签名如何工作
数字签名由两部分组成。第一部分是使用私钥从交易中创建签名,第二部分是允许任何人使用公钥来验证签名。

创建数字签名
ECDSA中:
Sig = F_sig ( F_keccak256 ( m ) , k ),其中:m是RLP编码的交易,k是签名私钥,F_sig是签名算法,Sig是产生的签名
F_sig产生了一个由两个值组成的签名Sig,通常称为R,S
Sig=(R,S)
被签名:交易(来自交易的哈希)
签名密钥:EOA私钥
签名结果:签名

验证签名
验证签名必须有签名(R和S)和序列化交易和公钥(与创建签名的私钥对应)。
验证签名代表着:只有生成此公钥的私钥的所有者才能在此交易上签名
如果签名对此消息有效,返回TRUE


※※※ECDSA数学--后续补上※※※


✨实践中的签名过程
要在以太坊签署交易,发件人必须:

  1. 创建一个包含九个字短的交易数据结构
    nonce、gasPrice、startGas、to、value、data、v、r、s(rs是ECDSA加密算法的输出值,即签名。v是用于恢复结果的ID)
  2. 生成交易的RLP编码的序列化消息
  3. 计算此序列化消息的Keccak256哈希
  4. 计算ECDSA签名,得到r和s

签名前缀v和公钥恢复
从ECDSA签名中计算签名者公钥称为公钥恢复
交易签名包含一个前缀值v,它告诉我么两个可能的R中哪一个是临时的公钥。(R和R'是公钥的两种可能性)
如果v是偶数,R是正确值。如果v是奇数,R'是正确值

离线签名(为了安全)

交易广播
以太坊网络使用“泛洪”路由协议。每个以太坊客户端,在_Peer-to-Peer(P2P)中作为_node,(理想情况下)构成_mesh_网络。没有网络节点是“特殊的”,它们都作为平等的对等体。 我们将使用术语“节点”来指代连接并参与P2P网络的以太坊客户端。
交易传播开始于创建(或从离线接收)签名交易的以太坊节点。交易被验证,然后传送到_直接_连接到始发节点的所有其他以太坊节点。平均而言,每个以太坊节点保持与至少13个其他节点的连接,称为_邻居_。每个邻居节点在收到交易后立即验证交易。如果他们同意这是有效的,他们会保存一份副本并将其传播给所有的邻居(除了它的邻居)。结果,交易从始发节点向外涟漪式地遍历网络,直到网络中的所有节点都拥有交易的副本。
几秒钟内,以太坊交易就会传播到全球所有以太坊节点。从每个节点的角度来看,不可能辨别交易的起源。发送给我们节点的邻居可能是交易的发起者,或者可能从其邻居那里收到它。为了能够跟踪交易的起源或干扰传播,攻击者必须控制所有节点的相当大的百分比。这是P2P网络安全和隐私设计的一部分,尤其适用于区块链。

写入区块链
虽然以太坊中的所有节点都是相同的对等节点,但其中一些节点由_矿工_操作,并将交易和数据块提供给_挖矿农场_,这些节点是具有高性能图形处理单元(GPU)的计算机。挖掘计算机将交易添加到候选块,并尝试查找使得候选块有效的_Proof-of-Work_。
不深入太多细节,有效的交易最终将被包含在一个交易块中,并记录在以太坊区块链中。一旦开采成块,交易还通过修改账户余额(在简单付款的情况下)或通过调用改变其内部状态的合约来修改以太坊单例的状态。这些更改将与交易一起以交易_收据_ receipt 的形式记录,该交易也可能包含_事件_ events。
我们的交易已经完成了从创建到被EOA签署,传播以及最终采矿的旅程。它改变了单例的状态,并在区块链上留下了不可磨灭的印记。


第八章 智能合约

  • 账户有两种:EOA和合约账户

  • EOA由以太坊以外的软件控制

  • 合约账户则由EVM内运行的软件控制

  • 以下将讨论合约账户和控制他们的软件:智能合约(smart contract)

  • 智能合约:Ethereum虚拟机环境中确定性的运行的不可变的计算机程序,该虚拟机作为一个去中心化的世界计算机而运转。

  • 每个合约都有以太坊地址表示,该地址源于合约创建交易,合约的以太坊地址可以在交易中作为接收者,可将资金发送到发送到合约或调用合约的某个功能。

  • 合约只有在被交易调用时才会运行,以太坊的所有智能合约均由交易执行。合约不会自动运行。

  • 合约的内容可以是调用另一个合约,连续的进行会产生一个合约链。

  • 合约不可被更改,但可以被删除。删除合约需要执行名为 SELFDESTRUCT(以前称为 SUICIDE )的EVM操作码,该操作花费负的gas。但这种操作不会删除合约的交易历史。

  • 合约里的交易是“原子性”的:交易的执行尽在交易成功终止的时候记录状态的更改(合约、账户等),而成功终止意味着程序执行的时候没有错误,如果交易由于出现错误而失败,所有效果(状态的变化)都会回滚,好像交易从未发生。但是失败的交易仍储存在区块链中,并从原始账户扣除gas成本,但对合约或账户状态没有其他影响。

  • 智能合约的生命周期:高级语言编写(solidity)-->编译为EVM中能运行的低级字节码-->跟随合约创建的交易被部署到以太坊区块链


以太坊中的高级语言

  1. EVM
    EVM是一台虚拟计算机,运行一种特殊形式的 机器代码 ,称为EVM 字节码,就像计算机CPU运行机器代码x86_64一样。
    我们使用高级语言编写程序并使用编译器将他们转化为字节码。
  2. 高级语言
    一般来说编程语言分为函数式(声明式)和过程式(命令式)
    在函数式中,我们编写的程序表达的是逻辑(logic)而非流程(flow),如SQL、HTML等。
    在过程式中,编写的是一套逻辑和流程混合在一起的程序,如C、C++、Java等。
    有一些编程语言是混合的,他们鼓励函数式编程,但也会用过程式表达一些必要的逻辑,如Python、JS等。
    Solidity是过程式语言,是最丰富的智能合约语言。
    目前的智能合约语言包括LLL、Serpent、Solidity、Vyper、Bamboo(从老到新)
  3. Solidty来写一个智能合约之前
    Solidity编译器:Solidity compiler(solc)
    集成开发环境:Remix IDE
    本地可以使用solc编译.sol文件
    $ solc --optimize --bin Faucet.sol
    solc的结果是产生一个可以交给以太坊区块链的十六进制序列化二进制文件
    以太坊合约应用程序二进制接口(ABI)
    ABI是两个程序模块之间的接口,通常,一个在机器代码级别,另一个在用户运行的程序级别。ABI是将数据编码到机器码,和从机器码解码数据的主要方式.
    在以太坊中,ABI用于编码EVM的合约调用,并从交易中读取数据。ABI的目的是定义合约中的哪些函数可以被调用,并描述函数如何接受参数并返回数据。
    合约ABI的JSON格式由一系列函数描述和事件的数组给出。
    solc为.sol文件生成ABI
    solc --abi Faucet.sol
    solc --abi Faucet.sol ======= Faucet.sol:Faucet ======= Contract JSON ABI [{"constant":false,"inputs":[{"name":"withdraw_amount","type":"uint256"}],"name":"withdraw","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"payable":true,"stateMutability":"payable","type":"fallback"}]
    如你所见,编译器会生成一个描述由 Faucet.sol 定义的两个函数的JSON对象。这个JSON对象可以被任何希望在部署时访问 Faucet 合约的应用程序使用。使用ABI,应用程序(如钱包或DApp浏览器)可以使用正确的参数和参数类型构造调用 Faucet 中的函数的交易。例如,钱包会知道要调用函数+withdraw+,它必须提供名为 withdraw_amount 的 uint256 参数。钱包可以提示用户提供该值,然后创建一个编码它并执行+withdraw+功能的交易。
    应用程序与合约进行交互所需的全部内容是ABI以及合约的部署地址。
    pragma solidity ^0.4.19;
    这个代码可以检测本地编译器版本和目标版本是否兼容

Solidity语法

Solidity完整文档https://solidity.readthedocs.io/en/latest/

Solidity数据类型
boolean (bool):布尔值, true 或 false, 以及逻辑操作符 ! (not), && (and), || (or), == (equal), != (not equal).
整数 (int/uint):有符号 (int) 和 无符号 (uint) 整数,从 u/int8 到 u/int256以 8 bits 递增,没有大小后缀的话,表示256 bits。
定点数 (fixed/ufixed):定点数, 定义为 u/fixedMxN,其中 M 是位大小(以8递增),N 是小数点后的十进制数的个数。
地址:20字节的以太坊地址。address 对象有 balance (返回账户的余额) 和 transfer (转移ether到该账户) 成员方法。
字节数组(定长):固定大小的字节数组,定义为+bytes1+到+bytes32+。
字节数组 (动态):动态大小的字节数组,定义为+bytes+或+string+。
enum:枚举离散值的用户定义类型。
struct:包含一组变量的用户定义的数据容器。
mapping:+key ⇒ value+对的哈希查找表。
除上述数据类型外,Solidity还提供了多种可用于计算不同单位的字面值:
时间单位:seconds, minutes, hours, 和 days 可用作后缀,转换为基本单位 seconds 的倍数。
以太的单位:wei, finney, szabo, 和 ether 可用作后缀, 转换为基本单位 wei 的倍数。
在withdraw函数中,我们限制最大提现额,将数量限制表示为wei,以太的基本单位:
require(withdraw_amount <= 100000000000000000);
这不是很容易阅读,所以我们可以通过使用单位倍数 ether 来改进我们的代码,以ether而不是wei表示值:
require(withdraw_amount <= 0.1 ether);

预定义的全局变量和函数
在EVM中执行合约时,它可以访问一组较小范围内的全局对象。这些包括 block,msg 和 tx 对象。另外,Solidity公开了许多EVM操作码作为预定义的Solidity功能。

调用交易/消息
msg:msg对象是启动合约执行的交易(源自EOA)或消息(源自合约)。它包含许多有用的属性:
msg.sender:我们已经使用过这个。它代表发起消息的地址。如果我们的合约是由EOA交易调用的,那么这是签署交易的地址。
msg.value:与消息一起发送的以太值。
msg.gasgasleft():这次交易携带的gas减去交易执行到现在的gas。它已经被弃用,并将被替换为Solidity v0.4.21中的 gasleft() 函数。
msg.data:调用合约的消息中的数据。
msg.sig:数据的前四个字节,它是函数选择器,可以让EVM明确的知道我们想调用的功能。
每当合约调用另一个合约时,msg的所有属性的值都会发生变化,以反映新的调用者的信息。唯一的例外是在原始msg上下文中运行另一个合约/库的代码的 delegatecall 函数。

交易
tx.gasprice:发起调用的交易中的gas价格。
tx.origin:源自(EOA)的交易的完整调用堆栈。

区块
block:包含有关当前块的信息的块对象。
block.blockhash(blockNumber)blockhash():指定块编号的块的哈希,直到之前的256个块。已弃用,并使用Solidity v.0.4.22中的blockhash()函数替换。
block.coinbase:当前块的矿工地址。
block.difficulty:当前块的难度(Proof-of-Work)。
block.gaslimit:当前块的区块gas限制。
每个区块都有gas limit,即单个区块允许的最多gas总量,可以决定单个区块中能打包多少笔交易。
我们每一次交易或合约调用都要设置一个gas limit,如果该次操作所使用的gas数量小于或等于您所设置的gas limit,则会被执行,但如果gas总消耗量超过gas limit,所有的操作都会被重置,但费用依旧会被收取。在执行中实际消耗的gas值总和叫gas used,没有使用完的gas会退还到原账号。
block.number:当前块号(高度)。
block.timestamp:矿工在当前块中放置的时间戳,自Unix纪元(秒)开始。
Unix 时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒

地址对象
任何地址(作为输入传递或从合约对象转换而来)都有一些属性和方法:
address.balance:地址的余额,以wei为单位。例如,当前合约余额是 address(this).balance。
address.transfer(amount):将金额(wei)转移到该地址,并在发生任何错误时抛出异常。我们在Faucet示例中的msg.sender地址上使用了此函数,msg.sender.transfer()。
address.send(amount):类似于前面的transfer, 但是失败时不抛出异常,而是返回false。
address.call():低级调用函数,可以用value,data构造任意消息。错误时返回false。
address.delegatecall():低级调用函数,保持发起调用的合约的msg上下文,错误时返回false。

内置函数
addmod, mulmod:模加法和乘法。例如,addmod(x,y,k) 计算 (x + y) % k。
keccak256, sha256, sha3, ripemd160:用各种标准哈希算法计算哈希值的函数。
ecrecover:从签名中恢复用于签署消息的地址。

合约定义

  • Solidity的主要数据类型是contract对象
  • 合约是一个包含数据和方法的容器
  • Solidity提供了另外两个与合约类似的对象:
    interface:常被称为 桩 stub,因为它告诉你有关函数的参数和返回值,没有任何实现,用来指定合约接口。
    library:库合约,是一个只能部署一次并被其他合约使用的合约。

函数
合约中定义了可有EOA交易或其他合约调用的函数(Faucet示例中有withdraw和fallback函数)
定义函数的语法:
function FunctionName([parameters]) { public|private|internal|external } [pure|constant|view|payable] [modifiers] [returns (<return types>)]
其中
FunctionName
定义函数的名称,用于通过交易(EOA),其他合约或同一合约调用函数。每个合约中的一个功能可以定义为不带名称的,在这种情况下,它是fallback函数,在没有指定其他函数时调用该函数。fallback函数不能有任何参数或返回任何内容。
parameters
在名称后面,我们指定必须传递给函数的参数,包括名称和类型。在我们的Faucet示例中,我们将uint withdraw_amount定义为withdraw函数的唯一参数。

关键字 public, private, internal, external)指定了函数的可见性:
public
Public是默认的
,这些函数可以被其他合约,EOA交易或合约内部调用。在我们的Faucet示例中,这两个函数都被定义为public。
external
外部函数就像public一样,但除非使用关键字this作为前缀,否则它们不能从合约中调用。
internal
内部函数只能在合约内部"可见",不能被其他合约或EOA交易调用。他们可以被派生合约调用(继承的)。
private
private函数与内部函数类似,但不能由派生的合约调用(继承的)。
请记住,术语 internal 和 private 有些误导性。公共区块链中的任何函数或数据总是可见的,意味着任何人都可以看到代码或数据。以上关键字仅影响函数的调用方式和时机。

关键字pure, constant, view, payable会影响函数的行为:
constant/view(constant被弃用)
标记为view的函数,承诺不修改任何状态。术语constant是view的别名,将被弃用。目前,编译器不强制执行view修饰器,只产生一个警告,但这应该成为Solidity v0.5中的强制关键字。
pure
纯(pure)函数不读写任何变量。它只能对参数进行操作并返回数据,而不涉及任何存储的数据。纯函数旨在鼓励没有副作用或状态的声明式编程。
payable
payable函数是可以接受付款的功能。没有payable的函数将拒绝收款,除非它们来源于coinbase(挖矿收入)或 作为 SELFDESTRUCT(合约终止)的目的地。在这些情况下,由于EVM中的设计决策,合约无法阻止收款。
正如你在Faucet示例中看到的那样,我们有一个payable函数(fallback函数),它是唯一可以接收付款的函数。

合约的构造和自毁
(构造函数和析构函数)
Solidity v.0.4.21,构造函数是一个名称与合约名称相匹配的函数
合约的生命周期始于EOA或其他合约的创建交易。如果有一个构造函数,它将在相同的创建交易中调用,并可以在创建合约时初始化合约状态。
constructor关键字,一般来说构造函数的函数名要与合约名字相同,但是可以使用
constructor ()
来代替
function contractName()
避免了重命名合约带来的错误,而且更容易确定哪个函数是构造函数。

`// Version of Solidity compiler this program was written for
pragma solidity ^0.4.22;

// Our first contract is a faucet!
contract Faucet {
address owner;
// Initialize Faucet contract: set owner
constructor() {
owner = msg.sender;
}`

合约生命周期的另一端是 合约销毁 contract destruction 合约被称为SELFDESTRUCT的特殊EVM操作码销毁。它曾经是SUICIDE,但由于该词的负面性,该名称已被弃用。在Solidity中,此操作码作为高级内置函数selfdestruct公开,该函数采用一个参数:地址以接收合约帐户中剩余的余额。看起来像这样:
selfdestruct(address recipient);

// Contract destructor function destroy() public { require(msg.sender == owner); selfdestruct(owner); }

函数修饰器 modifier
modifier onlyOwner { require(msg.sender == owner); _; }
这个函数修饰器onlyOwner为修饰的任何函数设置了条件,要求交易的msg.sender与合约的部署者owner相同。
占位符: _ ,此处由正在修饰的代码替换
使用函数修饰器,需要将其名称添加到函数声明,可以将多个修饰器作用于一个函数,以逗号分隔。
function destroy() public onlyOwner { selfdestruct(owner); }
这和上面的自毁函数相同
在修饰函数内部可以访问被修饰的函数的所有变量和参数,但是被修饰的函数无法访问修饰函数中的任何变量。

合约继承
继承合约为了附加功能,扩展基础合约,使我们实现模块化
继承合约使用 is 关键字指定父合约
支持多继承
contract Child is Parent1, Parent2 { }

错误处理 assert、require、revert
如果合约出现错误,所有的状态变化都会恢复,除了已花费的gas(这表明交易是原子性的,要么完成,要么对状态没有影响)。

  • assert和require函数以相同的方式运行:如果条件为假,则停止执行返回错误。一般来说,预期为真时使用assert,这意味着我们一般用assert来测试内部条件。在测试输入(如函数参数或交易字段)时使用require。
  • require函数是守护条件,阻止执行函数的其他部分,在不满足的时候产生错误。此外Solidity v.0.4.22开始,require还可以包含文本消息,用来显示错误的原因,所以我们可以在的require函数中添加一条错误消息:
    require(msg.sender == owner, "Only the contract owner can call this function");
  • revert函数停止合约并还原任何状态更改
  • 增加错误检查代码会略微增加gas小号,但他比不检查提供了更好的错误报告(在错误处理语句后面加上的错误信息)。需要开发者掌控两者间的平衡。

事件Events

  • event函数便于产生交易日志。
  • 当一个交易完成,会产生一个交易收据transaction receipt,包含log条目,用于提供有关在执行交易期间发生的操作的信息。事件是用于构造这些日志的Solidity高级对象。
  • 事件在轻量级客户端和DApps中特别有用,可以监视特定事件并将其返回给用户界面或者对应用程序的状态进行更改以反映底层合约中的事件
    尝试添加两个事件
    contract Faucet is mortal {
    event Withdrawal(address indexed to, uint amount);//记录了任何提款
    event Deposit(address indexed from, uint amount);//记录了任何存款
    ...
    }
    使用emit触发事件
    function withdraw(uint withdraw_amount) public {
    ...
    msg.sender.transfer(withdraw_amount);
    emit Withdrawal(msg.sender, withdraw_amount);//此处该在日志中记录,触发了提款事件
    }
    function () public payable {
    emit Deposit(msg.sender, msg.value);//此处该在日志中记录,触发了存款事件。
    //此处用于交易中没有合约中以声明的功能或不包含数据时触发。
    }

捕捉事件:
web3.js库提供了一个数据结构,包含交易日志的交易结果。在这里我们可以看到交易产生的事件。
Turffle:https://truffle.tryblockchain.org Turffle是基于以太坊Solidity语言开发的一套开发框架,基于JS。
使用Turffle在最新版的合约上运行测试交易:

  • 使用developed()函数获取部署后的合约。
  • 执行两个交易:第一个是存款(send),会触发Deposit事件
    Deposit { from: '0x627306090abab3a6e1400e9345bc60c78a8bef57', amount: BigNumber { s: 1, e: 18, c: [ 10000 ] } }
  • 第二个是提款,会触发Withdraw事件
    Withdrawal { to: '0x627306090abab3a6e1400e9345bc60c78a8bef57', amount: BigNumber { s: 1, e: 17, c: [ 1000 ] } }
  • res返回了logs数组(这个来自turffle),其中logs[0]包含logs[0].event的事件名字和logs[0].args的事件参数
  • 事件 这种机制不仅用于合约内通信,还用于开发过程中的调试。

合约调用(call、send、delegatecall、callcode)
调用其他合约:

  • 调用合约是有用但有危险的操作。越灵活的调用一般越危险。
  • 通过new实例化,这可以在区块链上创建合约并返回一个可以用于引用他的对象。
  • 如果不在一个文件内,用import
  • new可以用来传参 _faucet = (new Faucet).value(0.5 ether)();
  • 原始调用,delegatecall
    ⭐⭐⭐solidity->bytecode(字节码)->opcode(操作码) ⭐⭐⭐
    调用合约时可以使用更低级的功能,他们直接对应于相同名称的EVM操作码,这是一种盲调用(blind)。
    风险提示:安全风险如可重入性(reentrancy),如出现问题返回false
    delegatecall是call的变体,代替了更为危险的callcode。
    delegatecall不同于call,不会导致msg的上下文改变,应谨慎使用。
    call、delegatecall 和 callcode 是三种Solidity的合约间的调用方式⭐⭐⭐ call: 调用后内置变量 msg 的值会修改为调用者,执行环境为被调用者的运行环境(合约的 storage),最常用的调用方式。 delegatecall: 调用后内置变量 msg 的值不会修改为调用者(注:会改为以太坊账户的地址),但执行环境为调用者的运行环境。 callcode【v0.5.0时已禁用】: 调用后内置变量 msg 的值会修改为调用者,但执行环境为调用者的运行环境。

Gas控制
gas是智能合约编程中一定要考虑的因素
gas是限制以太坊允许交易损耗大最大量的资源,如果计算过程中超过了gas限制则:

  • 触发out of gas异常
  • 函数执行前的合约状态被恢复
  • 全部gas作为交易费用给矿工,不予返还
    gas由创建交易的用户支付,因此程序员应最大限度的较少合约函数的gas费用:
  • 避免动态大小的数组(有风险引入过多gas)
  • 避免调用其他合约(其他合约gas成本未知)
  • 要估算gas成本(JavaScript),这应该是开发流程的一部分
    这段可以根据调用参数估计执行合约所需gas单位--gasEstimate
    var contract = web3.eth.contract(abi).at(address); var gasEstimate = contract.myAweSomeMethod.estimateGas(arg1, arg2, {from: account});
    获取网格的价格
    var gasPrice = web3.eth.getGasPrice();
    估算gas成本
    var gasCostInEther = web3.fromWei((gasEstimate * gasPrice), 'ether');

安全

  • 所有智能合约都是公开的,任何用户都可以创建交易来与之交互,因此任何漏洞都可以被利用。
  • 智能合约领域的漏洞问题代价高昂。
  • 防御性编程的编程风格特别适用于智能合约编程:
  1. 极简/节约:用更少的办法、更少的代码、更少的复杂性和功能实现项目
  2. 代码重用:这是最基本的软件安全原则--最大限度的重用可信代码:即如果库和合约已经存在,请重复使用。如果一些代码片段多次使用,请作为函数或库来编写使用。
  3. 代码质量:采用严谨的工程和软件开发方法论来对待智能合约代码,而不是通用编程。
  4. 可读性:应该编写文档良好、易于阅读的代码,遵遁以太坊社区的一部分样式约定和命名约定。
  5. 测试覆盖:测试所有可能的输入。
  • 常见的安全风险:重入( Re-entrancy)
    当合约将一些以太币发送给一个未知地址时,外部恶意合约调用受攻击合约的上一个函数(如通过fallback回退函数),以类似递归的方法榨干合约里所有的以太。
    THE DAO事件中黑客就是使用了这种方法导致了以太坊的硬分叉

设计模式

  1. 访问控制 access control
  2. 状态流 state flow
  3. 资金支出 fund disbursement

部署智能合约

  • 测试智能合约
    测试框架:
    Truffle Test
    Embark Framework Testing
    DApp
    populus

在区块链上测试
在geth终端输入
eth.getTransactionReceipt(txhash);
可用于获得在txhash处的合约地址。
eth.getCode(contractaddress)
获取部署在contractaddress的合约代码。这可以用来验证正确的部署。
eth.getPastLogs(options)
获取位于地址的合约的完整日志,在选项中指定。这有助于查看合约调用的历史记录。
eth.getStorageAt(address, position)
获取位于 address 的存储,并使用 position 的偏移量显示该合约中存储的数据。


第九章 开发工具、框架、库

框架

  • Truffle

Github; https://github.com/Trufflesuite/Truffle
网站; https://Truffleframework.com
文档; https://Truffleframework.com/docs
Truffle Boxes; http://Truffleframework.com/boxes/
npm package repository; https://www.npmjs.com/package/Truffle

nodejs
npm
nvm(node版本管理器)
创建了一个包含DApp支持的Node.js版本的隐藏文件.nvmrc,这样开发人员只需要在项目运行nvm install 就会自动安装并切换该版本的nvm
继续使用npm -g安装truffle

使用一个预先构建的模版上的DApp
Truffle unbox <BOX_NAME>

创建Truffle项目
命名项目文件Faucet
初始化Truffle,目录结构:
.
├── contracts
│   └── Migrations.sol
├── migrations
│   └── 1_initial_migration.js
├── test
└── truffle-config.js
安装js支持包
安装truffle依赖

配置Truffle
truffle-config.js设置了一个默认的以太坊节点,该网络假定了我们正在运行以太坊客户端,既可以作为完整节点,也可以作为轻量型节点。
truffle-config.js指示了truffle与端口8545上的本地节点通过RPC进行通信。
truffle将使用本地节点连接任何以太网和测试网络,本地节点也会有钱包功能。
使用truffle部署合约
在contracts子目录中粘贴合约。
还可以执行truffle compile编译合约。
truffle migrations 理解部署脚本
truffle通过migrations.sol来跟踪哪些合约已经部署。如果一个项目拥有数十个合约和复杂的依赖关系,就不必为了尚未更改的合约支付gas。
migrations目录里有一个脚本1_initial_migration.js,它会部署Migrations.sol
include::code/truffle/Faucet/migrations/1_initial_migration.js var Migrations = artifacts.require("./Migrations.sol"); module.exports = function(deployer) { deployer.deploy(Migrations); };

我们需要第二个migrations脚本来部署Faucets.sol,可命名为2_deploy_contracts.js,只需要对1_initial_migration.js稍作修改。
include::code/truffle/Faucet/migrations/2_deploy_contracts.js var Faucet = artifacts.require("./Faucet.sol"); module.exports = function(deployer) { deployer.deploy(Faucet); };
准备好了后使用truffle migrate来部署合约

Embark
Github; https://github.com/embark-framework/embark/
文档; https://embark.status.im/docs/
npm package repository; https://www.npmjs.com/package/embark
$ npm -g install embark

OpenZeppelin
OpenZeppelin是Solidity的一个可重复使用的安全的智能合约的开放框架。
它由社区驱动,由 https://zeppelin.solutions/[Zeppelin] 团队领导。
最大的特点是安全。
使用时先将openzeppelin-solidity库安装到本地
npm install openzeppelin-solidity@1.9.0
openzeppelin可以和truffle很好的结合在一起。

zeppelin_os
zeppelin_os是一款开源的分布式工具和服务平台,位于EVM之上,可以安全的开发管理智能合约应用程序。
与OpenZeppelin的代码每次都需要重新部署每个应用程序不同,zeppelin_os的代码处于链上。

实用程序
ethereumJS helpeth: 命令行实用程序
helpeth是一个命令行工具,使开发人员更容易的操作密钥和交易。
它是基于JavaScript的库和工具集合ethereumjs的一部分。
https://github.com/ethereumjs/helpeth
Usage: helpeth [command]
dapp.tools
https://dapp.tools/
Dapp
https://dapp.tools/dapp/
Seth
https://dapp.tools/seth/
Hevm
https://dapp.tools/hevm/
SputnikVM
SputnikVM是一个独立的可插拔的用于不同的基于以太坊的区块链的虚拟机。它是用Rust编写的,可以用作二进制,货物箱,共享库,或者通过FFI,Protobuf和JSON接口集成。它有一个单独的用于测试目的的二进制sputnikvm-dev,它模拟大部分JSON RPC API和区块挖掘。
Github link; https://github.com/etcdevteam/sputnikvm

Libraries【库】
web3.js
web3.js是以太坊兼容的JS API,用于通过以太坊基金会开发的JSON RPC与客户进行通信。
Github link; https://github.com/ethereum/web3.js
npm package repository link; https://www.npmjs.com/package/web3
Documentation link for web3.js API 0.2x.x; https://github.com/ethereum/wiki/wiki/JavaScript-API
Documentation link for web3.js API 1.0.0-beta.xx; https://web3js.readthedocs.io/en/1.0/web3.html

web3.py
web3.py 是一个用于与以太坊区块链进行交互的Python库。它现在也在以太坊基金会的GitHub中。
Github link; https://github.com/ethereum/web3.py
PyPi link; https://pypi.python.org/pypi/web3/4.0.0b9
Documentation link; https://web3py.readthedocs.io/

EthereumJS
以太坊的库和实用程序集合。
Github link; https://github.com/ethereumjs
Website link; https://ethereumjs.github.io/

web3j
web3j 是Java和Android库,用于与Ethereum客户端集成并使用智能合约。
Github link; https://github.com/web3j/web3j
Website link; https://web3j.io
Documentation link; https://docs.web3j.io

Etherjar
Etherjar 是与Ethereum集成并与智能合约一起工作的另一个Java库。它专为基于Java 8+的服务器端项目而设计,提供RPC的低层和高层封装,以太坊数据结构和智能合约访问。
Github link; https://github.com/infinitape/etherjar

Nethereum
Nethereum 是以太坊的.Net集成库。
Github link; https://github.com/Nethereum/Nethereum
Website link; http://nethereum.com/
Documentation link; https://nethereum.readthedocs.io/en/latest/

ethers.js
ethers.js 库是一个紧凑,完整,功能齐全,经过广泛测试的以太坊库,完全根据MIT许可证获得,并且已收到来自以太坊基金会的DevEx资助以扩展和维护。
GitHub link: https://github.com/ethers-io/ethers.js
Documentation: https://docs.ethers.io

Emerald Platform
Emerald Platform提供了库和UI组件,可以在以太坊上构建Dapps。Emerald JS和Emerald JS UI提供了一组模块和React组件来构建Javascript应用程序和网站,Emerald SVG Icons是一组区块链相关的图标。除了Javascript库之外,它还有Rust库来操作私钥和交易签名。所有Emerald库和组件都使用 Apache 2许可。
Github link; https://github.com/etcdevteam/emerald-platform
Documentation link; https://docs.etcdevteam.com


第十章 Tokens

what's token
区块链中,Token是一种抽象概念,可以被拥有,代表资产、货币或者访问权

怎么使用Token
Token最明显的用途是数字私人货币,但也可以参与编程,提供许多功能。比如传达投票权、访问权和资源所有权。

  • 货币
    Token可以说一种货币形式,eth,bitcoin

  • 资源
    Token可以是共享经济或者资源共享环境中获得生成的资源,如网络共享的存储,cpu

  • 资产
    有形的或无形的,黄金,石油

  • 访问
    访问权限,对于数字或实体资产

  • 权益
    数字组织或者法律虚拟主体的股东权益

  • 投票
    数字或法律中的投票权

  • 收藏品

  • 身份
    头像或者身份证

  • 实际用途
    访问或支付

  • tonken分可替换的和不可替换的

  • 交易对手风险是交易中的其他方不能履行其义务的风险。

  • 基于区块链的token可以消除交易对手风险(共识规则的约束)

很多项目的发行都使用Token,用于为项目的服务支付。
一个新项目的Token分为实用Token(用于支付服务、应用程序、资源)和权益Token(代表初创团队股票的Token)
如果Token的应用环境非常下载,那么Token只有“微不足道的价值”。
采用Token是因为不使用Token就无法工作,而不是为了快速筹集资金。


✨Token标准✨


ERC20
ERC:以太坊征求意见
20:Github自动分配的发行号
目前绝大多数Token都基于ERC20,ERC20最终成为EIP20(以太坊改进建议)
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md
ERC20是可替换Token的标准,ERC标记的不同单元可互换,没有唯一属性

ERC必须的函数和事件

  1. totalSupply:返回当前存在的Token总数
  2. balanceOf:返回给定地址的余额
  3. transfer:给定一个地址和数量,将该数量的Tokens从执行该方法的地址的余额转移到该地址
  4. tranferFrom:给定发送人、接受人、数量,执行Token从一个账户转移到另一个账户,与approve一起使用
  5. approve:给定接受人地址和数量时,授权该地址从发布标准的账户执行多次转账,直到达到指定的数量
  6. allowance:给定所有者地址和消费者地址,返回该消费者被批准从所有者取款的剩余金额
  7. Transfer event:成功触发转移时的事件
  8. Approval event:成功调用approve的事件

ERC20可选函数

  1. name:返回Token可读的名称
  2. symbol:返回Token的人类可读符号
  3. decimals:返回用于分割Token的小数位数(如果为2,则将Token除以100以获取表示)

在Solidity中定义ERC20接口

在Solidity中ERC20接口规范的样子
contract ERC20 {
   function totalSupply() constant returns (uint theTotalSupply);
   function balanceOf(address _owner) constant returns (uint balance);
   function transfer(address _to, uint _value) returns (bool success);
   function transferFrom(address _from, address _to, uint _value) returns (bool success);
   function approve(address _spender, uint _value) returns (bool success);
   function allowance(address _owner, address _spender) constant returns (uint remaining);
   event Transfer(address indexed _from, address indexed _to, uint _value);
   event Approval(address indexed _owner, address indexed _spender, uint _value);
}

ERC20的数据结构
任何ERC20实现,它将包含两个数据结构,一个用于追踪余额,另一个用于追踪配额(allowances)。在Solidity中,它们使用data mapping(数据映射)实现。
第一个data mapping是允许Token合约跟踪谁拥有Token,
mapping(address => uint256) balances;
第二个data mapping是配额,允许花钱者从所有者的账户中花费特定金额,并通过二维映射追踪配额(从所有者地址映射到一个花费者地址和配额金额)
mapping (address => mapping (address => uint256)) public allowed;

ERC20的工作流程:transfer和approve&transerFrom

  • 一个是使用transfer进行的单次交易工作流程:
    如果爱丽丝希望向鲍勃发送10个Token,她的钱包会向Token合约的地址发送一个交易,并用Bob的地址和“10”作为参数调用transfer函数。Token合约调整Alice的余额(-10)和Bob的余额(10)并发出+Transfer事件。
  • 一个是使用approve和transferFrom的双交易工作流程:
    该工作流程允许Token所有者将其控制权委托给另一个地址,常用于委托控制权给合约来分配Token,但也可以被交易所使用。

假设Alice希望允许AliceICO合同将所有AliceCoin Token的50%卖给像Bob和Charlie这样的买方。首先,Alice发布AliceCoin ERC20合同,将所有AliceCoin发放到她自己的地址。然后,Alice发布可以以ether出售Token的AliceICO合同。接下来,Alice启动approve & transferFrom工作流程。她向AliceCoin发送一个交易,调用approve,参数是AliceICO的地址和totalSupply的50%。这将触发Approval事件。现在,AliceICO合同可以出售AliceCoin了。

当AliceICO从Bob那收到ether,它需要发送一些AliceCoin给Bob作为回报。在AliceICO合约内是AliceCoin和ether之间的汇率。Alice在创建AliceICO时设置的汇率决定了Bob将根据他发送给AliceICO的ether数量能得到多少Token。当AliceICO调用AliceCoin transferFrom函数时,它将Alice的地址设置为发送者,将Bob的地址设置为接收者,并使用汇率来确定将在“value”字段中将多少AliceCoin Token传送给Bob。AliceCoin合同将余额从Alice的地址转移到Bob的地址并触发 Transfer 事件。只要不超过Alice设定的审批限制,AliceICO合同可以调用 transferFrom 无限次数。AliceICO合同可以通过调用allowance函数来跟踪它能卖出多少AliceCoinToken。

实现ERC20
EIP20中提到了两种实现:

发布自己的ERC20

ERC20Token的问题
ERC20Token暴露了Token和ether之间的细微差别。

ERC223
一种Token合同接口标准
通过检测目的地地址是否是合同来解决无意中将Token转移到合同的问题。

ERC777
另一种改进的Token合同标准
https://github.com/ethereum/EIPs/issues/777

ERC721
ERC721提案是不可互换的 Tokens标准,也称为契据/deeds。
前面的所有Token标准是可互换的Token。

Token标准🪐

  • 什么是Token标准:
    是实现的最小范围,为了符合ERC20,你至少要实施ERC20规定的功能和行为。主要是鼓励合同之间的互用性,因此所有钱包、交易所、用户界面和其他的基础设施可以以可预见的方式与遵循任何规范的合同进行交流。

  • 复杂是安全性的敌人

  • 项目扩展常见功能
    所有者控制
    特定地址或一组地址(多重签名)具有特殊功能,例如黑名单,白名单,铸造,恢复等。
    燃烧
    Token燃烧是指Token被转移到不可靠的地址或删除余额并减少供应时故意销毁。
    Minting
    以可预测的速率添加Token的总供应量的能力,或通过Token创建者的“命令”添加的能力。
    Crowdfunding
    提供Token销售的能力,例如通过拍卖,市场销售,反向拍卖等。
    上限
    总供给的预定义和不可改变的限制,与“minting”功能相反。
    恢复“后门”
    恢复资金,反向传输或拆除由指定地址或一组地址激活的Token(多重签名)的功能。
    白名单
    限制Token传输仅限于列出的地址的功能。在经过不同司法管辖区的规则审核后,最常用于向“经认可的投资者”提供Token。通常有一种更新白名单的机制。
    黑名单
    通过禁止特定地址来限制Token传输的能力。通常有更新黑名单的功能。

  • Tokens和ICOs
    ICO:首次公开发售数字货币融资
    Token是重要组件
    目前在ethereum上的很多Token都是伪装的骗局、传销、集资。
    应该将这种技术的长期愿景和影响与Token ICO的短期泡沫区分开。
    泡沫中充斥着欺诈,但是Token标准和平台将存活下去,并有可能改变世界。


第11章 去中心化应用(DApps)

DApp
p2p使互联网用户连接到了一起
USENET是第一个p2p架构的分布式消息传递系统
Napster是一款音乐和文件共享应用,是完全点对点网络运动转化为BitTorrent的开始,参与用户完全独立于物理网络,无需遵守任何管理机构
DApp不属于单个服务器,而是将整个栈建在p2p网络上以分布式进行存储和操作。
一个DApp包括前端、后端和数据存储
DApp相比传统集中式架构有如下优点:

  1. 弹性:
    DApp不会有停机时间,只要区块链在,它就还在
  2. 透明
    允许任何人分叉代码,并在区块链上运行相同的应用程序
    任何与区块的互动都将永久储存
    任何有区块链副本的人都可以获得对他的访问权限
    可能无法将字节码反编译为源码并完全理解合约的代码
  3. 抗审查
    用户可以和DApp交互而不受集中机构的干扰,一旦在网络上部署代码,任何人都无法修改代码

DApp的组件

  1. 智能合约
    智能合约用于存储去中心化应用程序的业务逻辑、状态和计算
    将智能合约作为核心业务逻辑功能来运行的问题:
    部署后无法修改
    一个庞大的合约需要大量的gas来部署和运行。因此某些应用程序可能采取离线计算和外部数据源。
    DApp的核心业务逻辑以来与外部数据或服务器意味着你的用户必须信任这些外部事物
  2. 前端
    DApp的前端与传统的web前端没有什么不同
    前端与DApp的交互通常通过浏览器本身使用Mist浏览器或Metamask浏览器扩展等工具进行
    目前由于缺少可用作具有密钥管理功能等请客户端等移动客户端,没有创建移动DApp等项目
  3. 数据存储
    gas成本高,导致智能合约目前不适合存储大量数据。因此,多数DApp将利用去中心化存储(IPDS或Swarm)来存储和分发大量的静态资源。
    内容的哈希通常使用data mapping存储为智能合约中的字节,然后前端应用程序调用智能合约检索资产以获取每个资产等URL。
  4. 上链&脱链
  5. IPFS&Swarm
  6. 中心化数据

DApp框架

  1. Truffle
  2. Embark
    Embark专注于使用以太坊、IPFS和其他无服务器去中心化应用。
    区块链(以太坊):
    自动部署合约并使其在JS代码中可用。启动监视更改,如果你更新合约,Embark将自动重新部署合约(如果需要)和DApp。
    JS通过Promises使用合约。
    使用Javascript与合约进行测试驱动开发。
    跟踪已部署的合约; 只在真正需要时部署。
    管理不同的链(例如,测试网,私人网,livenet)
    轻松管理相互依赖合约的复杂系统。
    去中心化存储(IPFS):
    通过EmbarkJS轻松存储和检索DApp上的数据,包括上传和检索文件。
    将完整的应用程序部署到IPFS或Swarm。
    去中心化通信(Whisper,Orbit):
    使用Whisper或Orbit通过P2P发送/接收消息
    网络技术:
    与任何网络技术集成,React,Foundation等
    使用任何构建管道或工具,grunt,gulp,webpack
  3. Emerld Platform
    这是一个框架和工具集,简化了DApp的开发
    提供了:
    JS库
    常见图标
    管理私钥的Rust库
    集成组件或服务
    SputnikVM一个独立的EVM

活跃的DApp
以下列出了以太坊网络上的活跃DApp:
EthPM
一个旨在将包管理带入以太坊生态系统的项目。
Website:https://www.ethpm.com/
Radar Relay
DEX(去中心化交易所)专注于直接从钱包到钱包交易基于以太坊的tokens。
Website:https://radarrelay.com/
CryptoKitties
在以太坊上部署的游戏,允许玩家购买,收集,繁殖和销售各种类型的虚拟猫 它代表了为休闲和悠闲目的部署区块链技术的最早尝试之一。
Website:https://www.cryptokitties.co
Ethlance
Ethlance是一个连接自由职业者和开发者的平台,用ether支付和收款。
Website:https://ethlance.com/
Decentraland
Decentraland是以太坊区块链支持的虚拟现实平台。用户可以创建,体验内容和应用程序并从中获利。
Website:https://decentraland.org/


第十二章 预言机Oracles

EVM能保证相同的操作返回相同的输出,无论运行在什么地方。这保证了以太坊的安全,但阻止了智能合约检索和处理脱链数据,Oracles能解决这个问题。

Oracles可以定义为离线数据的权威来源,允许智能合约使用外部信息接收和条件执行---->也可以说Oracles是链接了链上链下之间的鸿沟的机制,允许了智能合约根据实际时间和数据强制,强制执行合约关系。

oracles提供的数据示例
物理量的随机数、自然灾害参数触发器、汇率数据、资本市场数据、基准参考数据、静态数据、事件和时间间隔、天气、政治、体育、地理位置、损害赔偿、其他区块链上的事件(互操作函数)、gas价格、航班

oracles的主要功能
回应去中心化应用的查询、解析查询、检查是否符合付款和数据权限、从脱链源中检索数据、在交易中签署数据、向网络广播交易、进一步安排交易

订阅模式
请求响应模式:常见于客户端-服务器体系
发布订阅模式:例如:发布者是oracles,不直接向用户发布信息,而是将发布的信息分到不同的类中。订阅者能够订阅多个类。此时orcales可以将利率写道自己的内部存储,当且仅当它发生变化时,多个DApp才从oracles中读取它,以减少对网络带宽的影响

数据认证
数据认证的任务是保证脱链方法返回的数据完整安全不被篡改。
数据认证常用的两种方法:

  • 真实性证明
    基于各种证明技术(如数字签名),有效的将信任从数据载体转移到了证明者
    Oraclize是一个利用真实性证明oracle服务的例子,目前可用于以太坊主网查询的是TLSNotary Proof。
    TLSNotary Proof依赖TLSNotary通过PageSigner签名,利用传输层安全性(TLS)协议,使对数据进行TLS签名的主密钥在三方之间分配:服务器(oracles)、受审核方(Oraclize)和审核员。
    Oraclize使用Amazon Web Service(AWS)作为审核员,来证明它实例化以来没有修改。
    这种方法要求亚马逊本身不会篡改实例
  • 可信执行环境(TEE)
    TownCrier是基于TEE的经过身份验证的数据发送系统,利用基于硬件的安全区域来验证数据的完整性。

计算oracle
oracles可用于执行任意计算,这在以太坊的环境中特别有用。

去中心化的oracle
集中式oracle系统虽然满足了许多应用,但也确实是以太网网络的中心故障点。
ChainLink提出了一个去中心化的oracle网络,包括三个关键的智能合约和数据提供商的脱链注册:

  • 信誉合约
    用于跟踪数据提供商的绩效
  • 订单匹配合约
    使用信誉合约选择出价
  • 汇总合约
    从多个oracles收集使用提交,ChainLink建议计算加权响应,并提供了一组标准的汇总合约。
    一个想法:SchellingCoin协议:将中位数作为答案

Solidity中的Oracle客户端接口
此处复杂,先学Solidity


第十三章 Gas

以太坊用于衡量执行一组动作所需计算量的单位,交易或者合约执行都需要一定量的gas。
gas具有双重作用:

  • 连接了以太坊价格和对矿工工作的奖励(和以太坊价格的波动性对抗)
  • 抵御拒绝服务攻击
    发送交易成本为21000gas、添加两个数字成本3个gas

停机问题
交易过载

支付gas
gas有价格,但不能被拥有和花费,仅存在于EVM内部,作为工作量的计数
收取ether--->转化为gas--->转回ether

gas价格、成本限制、耗尽
交易前发起方需要指定gas limit和gas price
gas limit多了,发起方收到退款
gas limit少了,交易失败,gas不退回

估算gas
通过假装交易已经被包含在区块链中来估算gas

代码
var result = web3.eth.estimateGas({
    to: "0xc4abd0339eb8d57087278718986382264244252f",
    data: "0xc6888fa10000000000000000000000000000000000000000000000000000000000000003"
});
console.log(result); // "0x0000000000000000000000000000000000000000000000000000000000000015"

gas价格和交易优先顺序
gas price设置的高一般回处理的更快

区块gas限制
Block gas limit是区块中允许的最大gas量,锁定了区块中可以容纳的交易数量
18年,区块gas限制在500w左右,可以容纳约238个交易,每个交易消耗21000gas
矿工决定了区块gas限制是什么,矿工可以对gas限制进行投票来扩容

gas退款
以太坊通过退还高达一半的gas费用来鼓励删除存储的变量
EVM中有2个负的gas操作:
清理合约是-24,000(SELFDESTRUCT)
清理存储为-15,000(SSTORE [x] = 0)

gasToken
gasToken是一种ERC20的Token,允许任何人在gas价格低时存储gas,在gas价格高时使用gas

租金
以太坊社区建议向智能合约收取“租金”来保持活力
不支付租金时,合约将被睡眠,简单的读取操作也无法进行,需要通过缴纳租金和提交merkle证据来唤醒睡眠的合约。

第十四章 EVM

EVM是实际处理内部状态和计算的协议部分,实际来看,EVM是包含数百万个对象的大型去中心化虚拟机

  1. 虚拟机(Virtualbox、云计算)和EVM的不同:
    虚拟机技术的目的是提供管理程序功能,或处理客户操作系统与底层操作系统和硬件之间的系统调用,任务调度和资源管理的软件抽象。
  2. JVM和EVM
    JVM和EVM比较相像。
    JVM旨在提供与底层主机操作系统或硬件无关的运行环境,从而实现各种操作系统的兼容性。
    在JVM上运行的高级程序语言(JAVA、Scala)被编译到相应的指令集字节码中。这与编译要在EVM上运行的Solidity源文件相当。

EVM机器语言
EVM的机器语言分为特定指令集合:
算术、逻辑和比较、控制流、系统调用、堆栈操作、存储器操作、管理账户、gas和区块信息

  1. 堆栈操作:
    堆栈和内存管理的操作码指令:
    POP // 项目出栈
    PUSH // 项目入栈
    MLOAD // 将项目加载到内存中
    MSTORE // 在内存中存储项目
    JUMP // 改变程序计数器的位置
    PC // 程序计数器
    MSIZE // 活动的内存大小
    GAS // 交易可用的gas数量
    DUP // 复制栈项目
    SWAP // 交换栈项目

  2. 算术运算
    通用算术运算代码指令:
    ADD //添加
    MUL //乘法
    SUB //减法
    DIV //整数除法
    SDIV //有符号整数除法
    MOD // Modulo(剩余)操作
    SMOD //签名模运算
    ADDMOD //模数加法
    MULMOD //模数乘法
    EXP //指数运算
    STOP //停止操作

  3. 环境操作码
    处理执行环境信息的通用操作码:
    ADDRESS //当前执行账户的地址
    BALANCE //账户余额
    CALLVALUE //执行环境的交易值
    ORIGIN //执行环境的原始地址
    CALLER //执行调用者的地址
    CODESIZE //执行环境代码大小
    GASPRICE //gas价格状态
    EXTCODESIZE //账户的代码大小
    RETURNDATACOPY //从先前的内存调用输出的数据的副本

状态
就像CPU跟踪执行过程一样,EVM必须跟踪各种组件的状态以支持以太坊交易。
以太坊也被描述为基于状态的虚拟机,包含以下组件

  1. World State
    160位地址状态标识符 和 账户状态 之间的关系,在不可变的默克尔树数据结构中维护。

  2. Account State
    包含以下四个组件
    nonce:从相应账户发送的交易数量的值
    balance:账户拥有的wei数量
    storageRoot:默克尔树根节点的256位哈希值
    codeHash:各个账户的EVM代码的不可变哈希值

  3. Storage State
    EVM上运行时维护的账户特定状态信息

  4. Block State
    交易所需的状态值包括
    blockhash:最近完成的块的哈希值。
    coinbase:收件人的地址。
    timestamp:当前块的时间戳。
    number:当前块的编号。
    difficulty:当前区块的难度。
    gaslimit:当前区块的gas限制。

  5. Runtime Environment Information
    用于使用交易的信息。
    gasprice:当前gas价格,由交易发起人指定。
    codesize:交易代码库的大小。
    caller:执行当前交易的账户的地址。
    origin:当前交易原始发件人的地址。

状态转换计算函数

  1. 以太坊状态转换函数
    用于计算_valid state transition_。

  2. 区块终结状态转换函数
    用于确定最终块的状态,作为挖矿过程的一部分,包含区块奖励。

  3. 区块级状态转换函数
    应用于交易状态时的区块终结状态转换函数的结果状态。

.sol编译为EVM字节码
solc命令
solc --help
使用 --opcode 命令编译后生成 .opcode 机器语言操作码文件
使用 --asm 命令编译后生成一个 .evm 的机器语言说明文件
使用 --bin 命令编译后生成一个字节码文件
使用 --bin-runtime编译后生成一个运行时字节码文件

执行EVM字节码

  • gas

  • 图灵完备性和gas
    图灵完备:系统可以解决你输入的任何问题。
    EVM理论上是图灵完备的,但是gas会组织它这么做。但对于大多数问题,EVM还是图灵完备的。

  • 字节码与运行时字节码
    编译时,会得到 合约字节码 和 运行时字节码。

  1. 合约字节码
    合约字节码是最终位于区块链上的字节码,加上将字节码放在区块链上并运行构造函数所需的字节码。

  2. 运行时字节码
    运行时字节码只是最终位于区块链上的字节码,不包括初始化合约并将其放在区块链上所需的字节码。

反汇编字节码


第十五章 共识(Consensus)

以太坊网络中,共识是指多个节点或代理在给定的时间点就区块链状态达成一致的能力。社区必须解决在技术上(网格内)和社交上(确保协议不会分叉和破裂)都达成共识。
以太坊可以更有效的抵御攻击,但在应对变化时却不那么果断。
获得共识和信任信息的能力将对区块链技术作为资产类别和技术的未来使用有着重要意义。为应对这一挑战并保持权力下放,社区不断尝试不同的共识模式。

共识度量
共识度量是可测量的数据,区块链网络的节点必须在该数据上达成一致。

每当新块添加到链中时,每个网络节点会测量并批准一致性度量。

作为共识度量的结果,区块链充当了从一个确定可验证的事实延伸到下一个事实的真理链。基于共识度量,区块链协议的节点变成迷你公证人(mini-notaries),它可以立刻从真实的节点中分辨出区块链的错误副本,并报告全网络,以便组织提交虚假信息的区块来欺骗网络。

基于一致性度量,区块链不仅建立了完整性,并保持长期不变。
共识度量有多种,最重要的两种是基于工作量的度量和基于风险的度量

POW
基于POW,度量间建立了共识:因为他们使用协议将计算机设置为查找难题的答案,即找到适合网络参数的散列的难题要求节点提交处理能力并使用电力与其他节点竞争以提出有效的哈希。

计算哈希很难,但验证是否是正确结果很简单。
比特币网络,平均每个区块生成的时间是十分钟。
以太坊网络,平均每个区块生成的时间是十秒。

基于风险的度量
基于风险的度量基于共识:选择创建无效区块的每个人都会失去比通过创建有效区块获得的更多的东西。
这种度量是通过链内数据的共识创造的,而不是pow那种链外共识。

pow的共识度量主要关注SHA-256哈希的质量和精确性
基于风险的度量的共识度量主要关注任何特定节点在添加新块时所承担的风险

  • Pos(权益证明)是一类共识算法
    在基于pos的区块链中,一组验证者轮流对下一刻进行建议和投票,每个验证者的投票权重取决于其存款大小
    pos的优势包括安全、降低集中风险、能源效率
    在Pos中任何人都可以都可以通过一种特殊交易成为验证者,参与创建和同意新块。
    从算法角度来看,pos又分为基于链的权益证明和BFT风格的权益证明:
    基于链的证明中,算法在每个时隙(10s)中伪随机的选择一个验证者,为该验证者分配创建单个块的权限。
    BFT 风格的权益证明中,验证者被随机分配提出区块的权利,但通过多轮过程来确定那个区块是规范的,其中每个炎症者在每轮中对特定区块投票,在流程结束后,所有(诚实并在线)的验证者永久同意任何给定的块是否属于链条一部分。

  • PoA
    PoA是pos的子集,常用于测试网、私有或联盟网络。
    poa的区块链中,交易有效性最终由一批经过批准的链上账户(授权节点)确定。
    poa是达成共识的最快途径

  • DPos(代理权益证明)
    dpos是一种修改的pos,网络参与者投票选举一系列代表来验证和和保护区块链。这可能类似poa,但是他们的权限可以被选民取消。

以太坊共识 Ethash
Ethash是pow,依赖于数据集的初始纪元产生,该数据集约1GB,是有向无环图(DAG)。

DAG使用 Dagger-Hashimoto算法的版本,它是Vitalik Buterin的Dagger算法和Thaddeus Dryja的Hashimoto算法的组合。Dagger-Hashimoto算法是以太坊1.0使用的挖掘算法。随着时间的推移,DAG线性增长,每纪元(30,000块,125小时)更新一次。

Polkadot简介
Polkadot是一种链间区块链协议,包括与权益证明(PoS)链的整合,允许Parachain在没有内部共识的情况下获得共识。


第十六章 Vyper:面向合约的编程语言

智能合约漏洞的基本类别:

  • 自杀合约
    可以被任意地址杀死的合约
  • 贪婪合约
    某个执行状态后无法释放ether
  • 浪费合约
    不经意间将ether释放到任意地址

Vtper是一种面向智能合约的实验性编程语言,面向EVM。
Vyper致力于通过简化代码并使其对人类可读而提供卓越的审计能力。Vyper的一个原则是让开发人员几乎不可能编写误导性代码。

与Solidity比较

  1. 修饰器
    Solidity中可以使用修饰器编写函数
    但将来修改修饰器会导致错误
    Vyper中删除了修饰器,使用内联检查和断言作为函数的一部分,提高了审计能力和可读性。

  2. 类继承
    类继承允许程序员从软件库中获取预先存在的功能、属性和行为。这可以促进代码的重用。
    Solidity支持多重继承和多态,这是面向对象编程的重要特性
    Vyper不支持,继承会导致编码人员和审计人员在多个文件之间跳转,这不利于理解程序。

  3. 内联汇编
    内联汇编允许开发人员以低级别访问EVM的机会,即在高级源代码中使用EVM操作码。
    Vyper不支持

  4. 函数重载
    具有相同名称和不同参数选项的多个函数定义
    foo(“hello”)和 foo(“hello”,“world”)

  5. 变量类型转换
    允许程序员将变量从一种数据类型转换为另一种数据类型的机制

  6. 前置条件和后置条件
    Vyper明确处理前置条件和状态更改。虽然会产生冗余,但确实更有可读性和安全性。
    Vyper编写合约时要考虑:
    条件:以太坊状态变量的当前状态/条件是什么
    效果:这个合约对执行状态变量的条件有什么影响,什么会被影响什么不会,这些影响是否和我们的意图一致
    交互:充分考虑代码执行的所有永久结果、后果和方案,包括与其他合约的交互

Vyper
Vyper打开了新的大门,偏离了传统的面向对象编程(OOP)

装饰符
类似@private、@public、@constant、@payable 这样的装饰符在每个函数开头声明。
@private:合约外部无法访问
@public:公开可见可执行
@constant:不允许变量改变
@payable:只有以@payable开头声明的函数才能接受价值

在线代码编辑器
Vyper拥有自己的在线代码编辑器

命令行运行
扩展名为 .v.py ,安装Vyper后,可以运行命令来编译和提供字节码

读写数据
智能合约可以将数据写入两个地方:以太坊的全球状态查找树或以太坊的链数据。

  • 全局状态
    给定智能合约中的状态变量,存储在以太坊的全局状态查找树中,给定的智能合约只能存储,读取和修改与该合约地址相关的数据(即智能合约无法读取或写入其他智能合约)。

  • Log
    智能合约也可以通过日志事件写入以太坊的链数据。最初Vyper用_log_语法来生命,但现在已经更新。目前是 MyLog: event({arg1: indexed(bytes[3])})

虽然智能合约可以写入以太坊的链数据(通过日志事件),但智能合约无法读取他们创建的链上日志事件。但可以在公共链上由轻客户端发现和读取日志。

ERC20接口
Vyper中ERC20上预编译合同,默认可用。Vyper中的合约必须声明为全局变量。如:
token: address(ERC20)

操作码(OPCODES)
合约一般用Solidity或Vyper等高级语言编写,编译器负责获取高级代码并创建他的低级解释,然后在EVM上运行。编译器可以提取代码的最低表示(在EVM执行前)是操作码。这种情况下需要高级语言的每个实现来提供适当的编译机制以允许将高级代码编译到通用预定义的EVM操作码中。
Vyper实现了以太坊的分片操作码


第十七章 DevP2P协议(ÐΞVp2p)

https://github.com/oldnicke/MasteringEthereum/blob/master/第十七章.asciidoc


第十八章 以太坊标准

EIPs
EIP代表以太坊改进提案。
EIP是一个设计文档,为以太坊社区提供信息,或描述以太坊或其过程或环境的新功能。
EIP应提供该功能的简明技术规范和该功能的基本原理。
EIP作者负责在社区内建立共识并记录不同意见。

ERCs
ERC代表以太坊征求建议。
如果EIP被接受,它将成为ERC的一部分


第十九章 以太坊分叉历史

多数的硬分叉作为路线图的一部分,包含社区普遍认同的更新,这被称为共识。
但也有一些硬分叉不是共识,这会导致多个不同的区块链,例如以太坊/以太坊经典。

以太坊经典(ETC)
2016年7月20日,在192w的区块高度上,以太坊通过硬分叉引入了改变,退还了360w的ether,这些ether来自名为The DAO的合约。

The DAO
DAO由Slock.lt创建,被视为基于社区,为项目提供资金的一种方式。
核心思想是提交提案,管理者管理提案,资金从以太坊的投资者筹集,如果项目成功,投资者将会获得收益。
DAO是以太坊token的一个实验。

重入bug(Re-Entrancy)
DAO攻击者从DAO中吸取了360w个ether。
RHG志愿者开始用相同的漏洞提取剩余的资金,并计划退还社区,保护了社区的大部分ether。

  • Re-Entrancy
    DAO攻击者发起多次请求,这允许了攻击者在合约记录攻击者成功提取之前,再次提取。

  • 攻击流程
    攻击者要求合约提取tokens
    在成功提取被记录之前,再次要求提取tokens
    尽可能重复上一步
    合约最终记录了一次DAO的提取,并失去了在此期间发生的取款

ETH和ETC

技术差异&意识形态差异





重要文档

  1. 以太坊基础相关文档
    以太坊黄皮书: https://ethereum.github.io/yellowpaper/paper.pdf
    褐皮书”:为更广泛的读者以不太正式的语言重写了“黄皮书”: https://github.com/chronaeon/beigepaper
    ÐΞVp2p 网络协议: https://github.com/ethereum/wiki/wiki/ÐΞVp2p-Wire-Protocol
    以太坊状态机 —— 一个“Awesome”资源列表 https://github.com/ethereum/wiki/wiki/Ethereum-Virtual-Machine-(EVM)-Awesome-List
    LevelDB 数据库 (最经常用于存储区块链本地副本): http://leveldb.org
    Merkle Patricia Trees: https://github.com/ethereum/wiki/wiki/Patricia-Tree
    Ethash 工作量证明共识算法: https://github.com/ethereum/wiki/wiki/Ethash
    Casper 权益证明 v1 实现指南: https://github.com/ethereum/research/wiki/Casper-Version-1-Implementation-Guide
    Go-Ethereum (Geth) 客户端: https://geth.ethereum.org/
    Parity 以太坊客户端: https://parity.io/

  2. 生成助记词,种子和扩展私钥的独立网页
    https://iancoleman.io/bip39/

  3. Solidity完整文档
    https://solidity.readthedocs.io/en/latest/

  4. 以太坊最佳安全开发指南
    https://github.com/ConsenSys/smart-contract-best-practices/blob/master/README-zh.md
    一个受到社区安全审查的库OpenZeppelin:https://openzeppelin.org/[OpenZeppelin] ,具有广泛的经过审查的简单行为
    一个用于安全的开发和管理智能合约的服务和工具的开源平台zeppelin_os:https://zeppelinos.org/[zeppelin_os] ,zeppelin_os在EVM上提供了一层,让开发人员可以轻松发布和升级DApp
    关于Ethereum ABI的更严格和更深入的解释可以在这找到: https://solidity.readthedocs.io/en/develop/abi-spec.html

    Github: https://github.com/ConsenSys/smart-contract-best-practices/
    Docs: https://consensys.github.io/smart-contract-best-practices/
    https://blog.zeppelin.solutions/onward-with-ethereum-smart-contract-security-97a827e47702
    https://medium.com/zeppelin-blog/the-hitchhikers-guide-to-smart-contracts-in-ethereum-848f08001f05#.cox40d2ut

  5. 合约库
    Github link: https://github.com/ethpm
    Repository link: https://www.ethpm.com/registry
    Website: https://www.ethpm.com/
    Documentation: https://www.ethpm.com/docs/integration-guide

  6. Swarm&IPFS
    Swarm主页: http://swarm-gateways.net/bzz:/theswarm.eth/
    阅读文档: https://swarm-guide.readthedocs.io/en/latest/index.html
    Swarm开发人员的入门指南: https://github.com/ethersphere/swarm/wiki/swarm
    Swarm讨论组: https://gitter.im/ethersphere/orange-lounge
    Ethereum’s Swarm 和 IPFS 的相似之处与不同之处; https://github.com/ethersphere/go-ethereum/wiki/IPFS-&-SWARM

  7. Truffle
    入门和文档:http://truffleframework.com/docs
    Github:https://github.com/trufflesuite/truffle
    Website:https://truffleframework.com

  8. Embark
    入门和文档:https://embark.readthedocs.io
    Github:https://github.com/embark-framework/embark
    Website:https://github.com/embark-framework/embark

  9. Emerald Platform
    入门和文档:https://docs.etcdevteam.com
    Github:https://github.com/etcdevteam/emerald-platform
    Website:https://emeraldplatform.io
    dapp_develotment_tool_sec:一个用于智能合约的命令行工具
    包管理、源代码构建、单元测试、简单的合约部署
    入门和文档:https://dapp.readthedocs.io/en/latest/

  10. 第十二章 Oracle预言机用到的

点击查看所有网站
http://www.oraclize.it/
https://tlsnotary.org/
https://tlsnotary.org/pagesigner.html
https://bitcointalk.org/index.php?topic=301538.0
http://hackingdistributed.com/2017/06/15/town-crier/
https://www.cs.cornell.edu/~fanz/files/pubs/tc-ccs16-final.pdf
https://www.crowdfundinsider.com/2018/04/131519-vitalik-buterin-outlines-off-chain-ethereum-smart-contract-activity-at-deconomy/
https://github.com/Azure/azure-blockchain-projects/blob/master/bletchley/EnterpriseSmartContracts.md
https://people.cs.uchicago.edu/~teutsch/papers/truebit.pdf
https://link.smartcontract.com/whitepaper
https://blog.ethereum.org/2014/03/28/schellingcoin-a-minimal-trust-universal-data-feed/
http://people.cs.uchicago.edu/~teutsch/papers/decentralized_oracles.pdf
https://developers.thomsonreuters.com/blockchain-apis/blockone-iq-ethereum
https://www.realitykeys.com

https://ethereum.stackexchange.com/questions/201/how-does-oraclize-handle-the-tlsnotary-secret
https://blog.oraclize.it/on-decentralization-of-blockchain-oracles-94fb78598e79
https://medium.com/@YondonFu/off-chain-computation-solutions-for-ethereum-developers-507b23355b17
https://blog.oraclize.it/overcoming-blockchain-limitations-bd50a4cfb233
https://medium.com/@jeff.ethereum/optimising-the-ethereum-virtual-machine-58457e61ca15
http://docs.oraclize.it/#ethereum
https://media.consensys.net/a-visit-to-the-oracle-de9097d38b2f
https://blog.ethereum.org/2014/07/22/ethereum-and-oracles/
http://www.oraclize.it/papers/random_datasource-rev1.pdf
https://blog.oraclize.it/on-decentralization-of-blockchain-oracles-94fb78598e79
https://www.reddit.com/r/ethereum/comments/73rgzu/is_solving_the_oracle_problem_a_paradox/
https://medium.com/truebit/a-file-system-dilemma-2bd81a2cba25 https://medium.com/@roman.brodetski/introducing-oracul-decentralized-oracle-data-feed-solution-for-ethereum-5cab1ca8bb64


  1. gasToken:了解计算盈利能力以及如何使用释放gas所涉及的数学
    https://gastoken.io/

  2. 合约租金
    ethereum/EIPs#35
    https://ethresear.ch/t/a-simple-and-principled-way-to-compute-rent-fees/1455 https://ethresear.ch/t/improving-the-ux-of-rent-with-a-sleeping-waking-mechanism/1480

  3. 反编译程序
    Porosity 是一个流行的开源反编译器:https://github.com/comaeio/porosity
    Ethersplay 是Binary Ninja的EVM插件,一个反汇编程序:https://github.com/trailofbits/ethersplay
    IDA-Evm 是IDA的EVM插件,另一个反汇编程序:https://github.com/trailofbits/ida-evm
    EVM工具:ByteCode To Opcode Disassembler (用于检查/调试编译是否完整运行,如果源代码未发布则可用于逆向工程)

  4. Vyper在线代码编辑器
    https://vyper.online

  5. ÐΞVp2p
    https://github.com/oldnicke/MasteringEthereum/blob/master/第十七章.asciidoc

  6. 以太坊改进提案(EIPs)
    https://eips.ethereum.org/

  7. 最重要的EIP和ERC表
    https://github.com/oldnicke/MasteringEthereum/blob/master/第十八章.asciidoc#最重要的eip和erc表

posted on   0x18  阅读(759)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5
点击右上角即可分享
微信分享提示