Contract
智能合约
xxx、xx
1 智能合约
发展历史
1990,xxxx提出智能合约概念
2009,比特币脚本
2015,以太坊智能合约 2015,超级账本 Fabric Chaincode
2017,FISCO BCOS发布
什么是智能合约
wj12
• 简单来说,“智能合约”就是一段可以运行在以 太坊上的代码。 之所以被称作“合约”,是因 为用户可以通过这段运 行在以太坊上的代码控 制有价值的事物,例如 ETH 或其他数字资产。
幻灯片 4
wj12 xxxxx://x0.xx.xxx/xxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/0000/00/xxxxxxxx.xxx?xxxxxxx000%0X000&xxxx0
xxx xxx, 2020/3/14
去中心化的代码
• 将现实世界的逻辑在区块链上实现
• 合约的内容和生命周期被共识确认,是大家认可的条款
• 在所有节点上保证逻辑的一致性
• 在所有节点上产生和维护一致的数据
• 合约可能有Bug,Bug也不可篡改
• Code is Law,是个理想目标
EVM
EVM
EVM
EVM
EVM
EVM
分布式环境
• 传统方式,信任依赖第三方,代码运行在第三方的服务器上。
• 有了区块链,信任就可以放在分布式网络上,合约代码在所有节点上执行、验证。
2 比特币脚本
比特币脚本
• 比特币的UTXO不一定被某个公钥持有,也可以被基于堆栈的区块链脚本持有,在被脚本持有的情况下,使用者必须提供满足脚本要求的数据才可使用该UTXO。例如,比特币区块链上可以创建要求集齐三把密钥中的两把才能使用的UTXO,即多重签名;也可以对解决某个数学问题的用户发送奖励。
• 比特币脚本存在一些严重的限制:
1. 缺少图灵完备性,尽管比特币支持多种运算,但不能支持所有的运算。最主要的确实是循环语句,不支持循环语句的目的是避免交易确认时 出现无限循环。理论上程序员可以利用多次的重复if来模拟,但这样导致空间上的低效率。
比特币脚本
• 比特币脚本存在一些严重的限制:
1. 缺少价值控制,比特币脚本无法为UTXO提供精确控制,由于UTXO是不可分割的,比特币脚本只能决定一次授予整个UTXO或否。唯一的方法是非常低效地生成许多不同面值的UTXO,并挑出正确的UTXO来使用。
2. 缺少状态,UTXO只能是已花费或者未花费状态,比特币脚本无法访问本UTXO以外的状态,这使得实现诸如期权合约、多阶段合约或者二元状态的合约变得非常困难,诸如限额的应用是不可能实现的。
比特币脚本 -- “交易”代码片段
“hash”: 交易ID
“ver”: 版本号
“vin_sz”: 输入的数量 “vout_sz”: 输出的数量 “lock_time”: 锁定时间 “size”: 交易规模
比特币脚本 -- 指令
数据指令 功能
<sig>
直接入栈
<pubkey> 直接入栈
操作符指令 功能
OP_DUP
复制堆栈顶端数据
OP_HASH160 计算哈希函数两次:第一次用 SHA – 256,第二次用 RIPEMD – 160
OP_EQUALVERIFY
如果输入是相同
如果输入是不同
返真
返假,整个交易作废
OP_CHECKSIG 检查输入的签名是否有效
OP_CHECKMULTISIG
检查在交易中 t 个公钥(地址)对应的 t 个签名是
否有效
<sig> <pubkey> 数据指令
比特币脚本 – P2PH脚本
scriptSig
scriptPubKey
把当前交易的输入脚本和上一笔交易的输出脚本连接起来,形成一个新脚本。矿工执行新脚本,结果返 true 表示支付成功。
比特币脚本 -- 脚本执行的堆栈状态
1
2
3
4
5
6
7
3 以太坊智能合约
Xxxxxxx Xxxxxxx
wj2
幻灯片 15
wj2 xxxxx://xxx.xxxxxxxx.xxx/xxxxx/xxxxxxxx-000/xxx-xxxxxxx-xxxxxxxx
xxx xxx, 2020/3/7
以太坊智能合约 -- 区块链层次结构
应用程序
RPC
以太坊 EVM
P2P网络
共识
激励
账本
底层调用库及存储
这个层次结构适合目前市面上所有的区块链平台
以太坊智能合约 -- 图灵完备
• 智能合约可以执行普通计算机可以执行的任何操作,尽管与常规 计算机相比,区块链版本的运行速度要慢得多并且运行成本更高,这取决于区块链的设置。
wj9
• 理论上,可以将任何逻辑放入以太坊智能合约中,并由整个网络运行。
• 支持循环、跳转、判断、分支等语句。
• 支持多种数据类型。
• 支持面向对象编程。
• 可应对图灵停机问题。
幻灯片 17
wj9 xxxxx://xx.xxxx.xxx/ images/search?view=detailV2&ccid=uxjdjk6W&id=0D6A65D3FD59B00A20396764B2E315DEF7BB604F&thid=OIP.uxj wei jia, 2020/3/13
以太坊智能合约 -- 数据一致性
• 以太坊是一个交易驱动的状态机。
• 调用智能合约的交易发布到区块链上后,每个矿工都会执行这个交易,从当前状态确定性地转移到下一个状态。
• 智能合约在沙箱运行,不能访问时钟、网络、文件等不确定性系统。
• 所有节点的运行结果必须保持一致,经过共识的运行结果才能记录上链。
全网共识
Block
Tx Tx Tx
EVM
Sandbox
Code
TxPool
Tx Tx Tx Tx Tx Tx Tx
Tx
Miner node
Full nodes
Blockchain
全网
共识
Storage
DAPP
EVM
Code
Block
Tx Tx Tx
以太坊智能合约 -- 合约上链执行
Block | Block | Block | Block | |||
Tx
TxData: contract code called
external account address
contract account address
From:
To:
…
DAPP发起一个合约调用的交易,交易广播至全网,进入交易池,矿工从交易池取出交易,将 交易放到EVM中运行,运行完成后将交易打包到区块中,发布区块,经全网共识,区块入链。
以太坊智能合约 -- 驱动状态变化
账户
合约
交易
EVM
• 以太坊是一个状态机
• 由账户发起一笔交易
• 创建 EVM 虚拟机
• 装载合约代码并执行
• 合约执行结果使得账户状态发生改变
以太坊智能合约 -- 应用
• 加密货币钱包:让你可以使用 ETH 或其他数字资产进行低成本的即时支付。
• 金融应用程序:让你可以借贷、投资数字资产。
• 去中心化市场:让你可以交易数字资产,甚至就现实世界事件的 “预测”进行交易。
• 游戏:你可以拥有游戏内的资产,甚至可以由此获得现实收益。
账户
Account
Account State Nonce
balance
hash
storage
Address
• 帐户保存了合约当前的运行状态
• Externally Owned Accounts (EOAs),外部账户,用户通过私钥控制
• Contract Accounts,合约账户,由合约代码控制,由EOA发起调用
账户
• Address: 20-bytes(160bit), 从公钥计算得来。
• nonce:如果是外部账户,表示从这个账户发出的交易个数;如果是合约账户,表示这个账户创建的合约个数。
• balance:账户余额,以“卫”为单位,每个以太是10的18次方个“Wei”。
• StorageRoot:存储该账户相关的Merkle Xxxxxxxx Xxxx的根hash。
• codeHash:如果是外部账户,它是空字符串的hash,如果是合约账户表示EVM代码的hash。
账户 -- 类型
Externally Owned Account
Account State Nonce
balance
hash
storage
Address
Contract Account
Account State Nonce
balance
hash
storage
Address
Externally Owned Account的storage和hash为空
账户 -- 创建外部账户地址
Keccak256()
160 bits
Public Key
256 bits
Private key
ECDSAPUBK()
EOA
Address
For a given private key, the Ethereum address (a 160-bit value) to which it corresponds is defined as the rightmost 160-bits of the Keccak hash of the corresponding ECDSA public key.
账户 -- 创建合约账户地址
RLP()
Nonce
EOA
Address
256 bits
Keccak256()
160 bits
RLP
Encoding
Contact Address
The address of the new account is defined as being the rightmost 160 bits of the Keccak hash of the RLP encoding of the structure containing only the sender and the account nonce.
World State
Account State
Account State
Account State
Account State
Address4
Address3
Address2
Address1
账户 -- World State
• World State世界状态就是所有账户状态的总和。
• World State 以 Merkle Patricia Tree的结构存储。
root=h(hl+hr)
账户 -- MPT -- Merkle Tree
hr=h(h12+h34) | hr=h(h56+h7) | |
h12=h(h1+h2) h34=h(h3+h4) | h56=h(h5+h6) | |
h1=h(tx1) h2=h(tx2) h3=h(tx3) h4=h(tx4) | h5=h(tx5) h6=h(tx6) | h7=h(tx7) |
tx1 tx2 tx3 tx4 | tx5 tx6 | tx7 |
• 难篡改,易验证。轻节点只需要存区块头 – 区块头中包含了树根 -- 就可以验证交易支付。
• 比特币的交易树就是Merkle Tree,以太坊没有直接使用Merkle Tree,但使用了这一特性。
• 相比于链表使用内存地址作为指针, Merkle Tree使用hash值作为指针。
B
E
L
S
T
O
T
T
C
O
E
K
M
R
账户 -- MPT -- Trie
Be Better Best Block Bloom
• Trie 结构要先排序
• 经过排序之后,树的状态是唯一的
• 方便检索、查找
账户 -- MPT -- Trie
B
E
L
S
T
O
T
T
C
O
E
K
M
R
路径
B
E
LO
ST
TTER
CK
OM
账户 -- MPT -- Merkle Xxxxxxxx Xxxx
账户 -- MPT -- Merkle Xxxxxxxx Xxxx
• Modified Merkle Xxxxxxxx Xxxx Specification (Merkle Xxxxxxxx Xxxx)
• Merkle Patricia Trie 节点类型:
1. NULL (represented as the empty string)
2. branch A 17-item node [ v0 ... v15, value ]
3. leaf A 2-item node [ encodedPath, value ]
4. extension A 2-item node [ encodedPath, key ]
• Merkle Xxxxxxxx Xxxx 优点:
• 容易插入,修改
• 经过排序,结构唯一确定
• xxxxx://xxxxxx.xxx/xxxxxxxx/xxxx/xxxx/Xxxxxxxx-Xxxx#xxxxx- resources
账户 -- 状态变迁
区块链是一个状态机模型
State N
State N + 1
State N + 2
State N + 3
Block
Tx Tx
Tx
Block
Tx Tx
Tx
Block
Tx Tx
Tx
账户 -- 状态变迁
交易
• 交易(Transaction):由外部参与者签名的一条数据。 它代表消息或新的自治对象。 交易记录在区块链的每个区块中。
• 消息(Message):通过自治对象(合约)的确定性操作或交易的加密安全签名,在两个帐户之间传递的数据(作为一组字节)和值(指定为以太币)。
• 消息调用(Message Call):将消息从一个帐户传递到另一个帐户的行为。 如果目标帐户与非空的EVM代码相关联,则将以所述对象的状态启动VM,并执行消息。如果消息发起者是自治对象,则调用将传递从VM操作返的所有数据。
xxxxx://xxxxxxxx.xxxxxx.xx/xxxxxxxxxxx/xxxxx.xxx
交易 -- 转账
Transaction
from to value
data
a3fa29ce
bd2ba9b1 30 eth
Next State
a3fa29ce 920 eth
bd2ba9b1 30 eth
Previous State a3fa29ce 950 eth
bd2ba9b1是个新地址,将其更新到状态树中。
Address 为 a3fa29ce 的账户给Address 为 bd2ba9b1 的账户转30个eth。
交易 -- 转账
Transaction
from to value
data
a3fa29ce
bd2ba9b1 10 eth
Next State
a3fa29ce 910 eth
bd2ba9b1 40 eth
Previous State
a3fa29ce 920 eth
bd2ba9b1 30 eth
Address 为 a3fa29ce 的账户给Address 为 bd2ba9b1 的账户转10个eth。
交易 -- 创建合约
Next State
a3fa29ce
cd4na61t
919.99 eth
codehash
Transaction
from to value data
gas
a3fa29ce 0x0
0
bytecode
0.01 eth
Previous State a3fa29ce 920 eth
Address 为 a3fa29ce 的账户部署合约,生成一个新合约账户 cd4na61t,将其更新到状态数。
交易 -- 调用合约
Previous State
a3fa29ce
cd4na61t
919.99 eth
codehash storage1
Next State
a3fa29ce
cd4na61t
919.98 eth
codehash storage2
Transaction
from to value data
gas
a3fa29ce cd4na61t 0
set(),arg
0.01 eth
Address 为 a3fa29ce 的账户调用 cd4na61t 的合约中的helloWord方法,同时消耗0.01eth。 Param
消息 -- 调用合约
State
a3fa29ce
cd4na61t
919.99 eth
codehash
State
a3fa29ce
cd4na61t
919.99 eth
codehash
Message
from to value data
gas
a3fa29ce cd4na61t 0
get()
0
Address 为 a3fa29ce 的账户调用 cd4na61t 的合约中的 get() 方法,不消耗gas。不更新账本,不更新状态树。
消息调用 -- Message Call
Message
Message
Externally Owned Account
Contract Account
Contract Account
消息调用(Message Call):将消息从一个帐户传递到另一个帐户的行为。 如果目标帐户与非空的EVM代码相关联,则将以所述对象的状态启动VM,并执行消息。如果消息发起者是自治对象,则调用将传递从VM操作返的所有数据。
xxxxx://xxxxxxxx.xxxxxx.xx/xxxxxxxxxxx/xxxxx.xxx
交易 -- 生命周期
EVM
Code
Miner node
交易请求
Node 广播交易 挖矿
DAPP
TxPool
…
Tx Tx Tx Tx
判断交易类型
创建合约账户,更新
World State
打包区块
Block
检查余额,更新Word State
…
Tx Tx Tx
Blockchain
World state
广播区块
Full nodes
Block | Block | Block | ||
Storage
全网共识
交易 -- 节点数据
Full nodes
Block
Block
Block
Blockchain
Block
Block
Block
Trans Trie
Receipts Trie
Trans Trie
Receipts Trie
Trans Trie
Receipts Trie
World state Trie
Database
Solidity -- 智能合约语言
• 以太坊虚拟机 (EVM) 上运行的程序通常被称作“智能合约”。
• Solidity 以太坊上最受欢迎的智能合约语言,灵感来自 C++、 Python 和 JavaScript
• Solidity 智能合约可以接收和储存价值,也可以向外发送信息和价值。
• EVM为 Solidity 智能合约提供运行的沙盒环境,对外隔离。
• EVM无法访问网络、文件系统其它进程,智能合约在EVM内只允许进行有限的操作。
• 为防止滥用,运行合约需要支付费用。
Solidity – 示例
pragma solidity >=0.4.22 <0.6.0;
声明 solidity 版本号
wj1
contract Token {
mapping (address => uint) public coinBalanceOf;
event CoinTransfer(address sender, address receiver, uint amount); constructor() public {
if (supply == 0) supply = 10000; coinBalanceOf[msg.sender] = supply;
合约关键字状态变量
事件日志
构造方法,创建合约时调用
}
function sendCoin(address receiver, uint amount) public returns(bool sufficient) { if (coinBalanceOf[msg.sender] < amount) return false; coinBalanceOf[msg.sender] -= amount;
coinBalanceOf[receiver] += amount; CoinTransfer(msg.sender, receiver, amount); return true;
成员函数
}
}
幻灯片 45
wj14 xxxxx://x0.xx.xxx/xxxxxxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/0000/00/xxxxxxxx-xxxxx.xxx?xxxxxxx000%0X000&xxxx0
xxx xxx, 2020/3/18
Solidity -- 编写合约
Solidity -- 创建合约
• 创建智能合约之前,合约代码要编译成bytecode,
• 创建合约:外部帐户发起一个到0x0地址的交易
• 转账的金额(value)为0
• 需要支付汽油费(gas)
• Code放在数据域( data )
• 以太坊是一个交易驱动的状态机,转账交易或合约调用交易经过执行、共识之后,以太坊从当前状态确定性地转移到下一个状态
Solidity -- 创建合约
Next State
Transaction
0.01 eth
gas
code
data
0
value
0x0
to
a3fa29ce
from
n
nonce
codehash
cd4na61t
919.99 eth
a3fa29ce
Previous State a3fa29ce 920 eth
Address 为 a3fa29ce 的账户创建合约,最后生成一个新合约账户 cd4na61t 。
Solidity -- 外部账户调用合约
• 创建一个交易,接收地址为要调用的那个智能合约的地址,data域填写要调用的函数及其参数的编码值。
Previous State
a3fa29ce
cd4na61t
919.99 eth
codehash storage1
Next State
a3fa29ce
cd4na61t
919.98 eth
codehash storage2
Transaction
from to value data
gas
a3fa29ce cd4na61t 0
set(),arg
0.01 eth
Solidity -- 外部账户调用合约
Solidity -- 外部账户调用合约
<script src="xxxxx://xxx.xxxxxxxx.xxx/xx/xxxxxxxx/xxx0.xx/xxxx/xxx0.xxx.xx"></script> | ||
<script> | { | { |
web3 = new Web3(web3.currentProvider) | "constant": false, | "constant": true, |
// The interface definition for your smart contract (the ABI) | "inputs": [ | "inputs": [ |
var HelloWorld = web3.eth.contract([ ]); | { | { |
// Grab the contract at specified deployed address with the interface defined by the ABI | "name": "id", | "name": "id", |
var helloWorld = XxxxxXxxxx.xx('0xfcB8C8696a778A7d9139c39f25Ae69b1cb9D0fD9'); | "type": "uint256" | "type": "uint256" |
helloWorld.set.sendTransaction(id, name | }, | } |
{from:account, gas:0000000}, | { | ], |
function (error, result){ | "name": "name", | "name": "get", |
if (!error) | "type": "string" | "outputs": [ |
alert("TxHash: " + result); | } | { |
xxxx | ], | "name": "", |
alert(error); | "name": "set", | "type": "string" |
}); | "outputs": [], | } |
xxxxxXxxxx.xxx.xxxx(id, function(error, result){ | "payable": false, | ], |
if (!error) | "stateMutability": "nonpayable", | "payable": false, |
let r = result; | "type": "function" | "stateMutability": "view", |
else | }, | "type": "function" |
alert(error); | } | |
}); </script> | ABI |
Solidity -- 合约调用合约
Contract A
Contract B
Message
function2
function1
calldata
function
• 一个合约可以通过消息调用的方式调用另一个合约
• 消息调用包括 source, target, data payload, Ether, gas and return data
• 合约A调用合约B时,A提供存储区域calldata。B 访问payload ,执行结束后,把数据存储在A的calldatax
Solidity -- 合约调用合约
contract A {
function sum(uint a, uint b) external returns (uint) { return a + b;
}
}
contract C {
function callA(address addr) public returns (uint) {
contract B {
function callA(address addr) public returns (uint) { A a = A(addr);
return a.sum(1, 1);
}
}
bytes memory payload = abi.encodeWithSignature("sum(uint a, uint b)", 1, 1); (bool success, uint memory returnData) = address(addr).call(payload);
return returnData;
}
}
Solidity -- 合约调用合约
• 使用方法与call()相同,但不能使用.value()
• delegatecall不切换上下文 ,call()切换到被调用合约上下文
• msg.sender和msg.value不变
• delegatecall 的目的是使用存储在另外一个合约中的库代码。
contract C {
function callA(address addr) public returns (uint) {
bytes memory payload = abi.encodeWithSignature("sum(uint a, uint b)", 1, 1); (bool success, uint memory returnData) = address(addr).delegatecall(payload); return returnData;
}
}
EVM -- Ethereum Virtual Machine
• The Ethereum Virtual Machine or EVM is the runtime environment for smart contracts in Ethereum. It is not only sandboxed but actually completely isolated, which means that code running inside the EVM has no access to network, filesystem or other processes. Smart contracts even have limited access to other smart contracts.
• With ethereum, every time a program is used, a network of thousands of computers processes it.
• Contracts written in a smart contract-specific programming languages are compiled into ‘bytecode’, which a feature called the ‘ethereum virtual machine’ (EVM) can read and execute.
• All the nodes execute this contract using their EVMs.
EVM 详解
• EVM是供智能合约运行的沙盒环境,与外部环境完全隔离
• EVM无法访问网络、文件系统其它进程,智能合约在EVM内只允许进行有限的操作
• EVM为哈佛架构的虚拟机,指令、数据和栈完全分离
• EVM执行流程:
1. 调用方传入调用智能合约的参数到区块链底层:address、data和value
2. 区块链底层到存储中查找address对应的合约账户,读出合约账户的code数据
3. 区块链底层初始化一个新EVM,将data和value放入memory,并根据code启动EVM
4. EVM解析data的参数,开始执行
5. EVM执行完成后,返值放入memory
6. 区块链底层从memory获取返值,传给调用方
EVM APP
wj4
幻灯片 57
wj4 xxxxx://xxx.xxxxxxxx.xxx/xx-xxxxxxx/xxxxxxx/0000/00/Xxxxxx-Xxxx-0000-00-00-xx-0.00.00-XX.xxx
xxx xxx, 2020/3/7
ALU
Storage
key => value 256 => 256
Input Data
EVM 架构
Top
16 * 256 bits
1024 * 256 bits
Stack
PC指针
EVM
Code
Memory
8 bits or
256 bits
Contract Account
EVM 指令
Instruction | Explanation | ||
stop() | - | F | stop execution, identical to return(0, 0) |
add(x, y) | F | x + y | |
sub(x, y) | F | x - y | |
mul(x, y) | F | x * y | |
div(x, y) | F | x / y or 0 if y == 0 | |
sdiv(x, y) | F | x / y, for signed numbers in two’s complement, 0 if y == 0 | |
mod(x, y) | F | x % y, 0 if y == 0 | |
smod(x, y) | F | x % y, for signed numbers in two’s complement, 0 if y == 0 |
xxxxx://xxxxxxxx.xxxxxxxxxxx.xx/xx/x0.0.0/xxx.xxxx#xxxxxxx
开发者工具
• Truffle 开发环境、测试框架、构建管道及其他工具
• ZeppelinOS 一种开发框架,用于构建可升级智能合约,并安全地管理智能合约应用程序。
• Visual Studio Code 以太坊官方支持的专业跨平台 IDE
• Remix 基于 Web 的 IDE,内置静态分析和区块链测试虚拟机
• xxxxx.xxxxxxxx.xxx
• Ropsten 工作量证明区块链,可以对测试以太币进行挖矿
Rinkeby 权威证明 (PoA) 区块链,由 Geth 开发团队维护
4 Fabric Chaincode