This page looks best with JavaScript enabled

《Mastering Ethereum》笔记及EVM字节码逆向

 ·  ☕ 8 min read · 👀... views

Background

机缘巧合,5-18面了某蓝厂web3&区块链部门,遂想了解一下web3&区块链。

看了一些视频,了解了Web3、DApp、DeFi、GameFi等概念。

两三天时间肝完了《Mastering Ethereum: Building Smart Contracts and DApps》。

了解了以太坊设计理念,钱包、交易、代币、预言机,安全策略,安全漏洞攻击方式及修复方式;对最新版本编译器生成的EVM字节码进行分析;发现并递交了书中出现的多个错误。

可以说是收获颇丰,写篇博客做下笔记和回顾。

一、What is Ethereum

Bitcoin: peer to peer cash system
Ethereum: Smart contracts and DApps infrastructure

turing complete
gas beat DOS

二、Basic concept

单位
10**18 wei == 10**9 shannon(gigawei) == 1 ether

metamask ropsten faucet

三、客户端

geth(go)
parity(rust)
json-rpc port 8545

四、密码学

简单ECC&ECDSA

以太坊地址:
K(pub) = k(pri)*G
addr = Keccak256(K)[-20:]

五、钱包

钱包种子 助记词

六、交易

nonce
gas price
gas limit
recipient
value
data
v,r,s

递归长度前缀(RLP)编码

合约账户 外部账户
合约创建地址0x0

七、Solidity

1
2
3
# binary code
solc --optimize --bin Faucet.sol
solc --abi Faucet.sol
 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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
// SPDX-License-Identifier: CC-BY-SA-4.0
pragma solidity 0.8.14;

// base contract
contract Owned  {
    address payable owner;
    constructor (){
        owner = payable(msg.sender);
    }
    // function decorator
    modifier onlyOwner {
        // tx.origin unsafe
        require(msg.sender == owner);
        _;
    }
}

// child contract
contract Mortal is Owned  {
	// Contract destructor
	function destroy() public onlyOwner {
		selfdestruct(owner);
	}
}

contract Faucet is Mortal {
    // function FunctionName([parameters]) {public|private|internal|external}
    // [pure|view|payable] [modifiers] [returns (return types)]

    event Withdrawal(address indexed to, uint amount);
    event Deposit(address indexed from, uint amount);

    // Accept any incoming amount
    receive() external payable {
        emit Deposit(msg.sender, msg.value);
    }
    // Give out ether to anyone who asks
    function withdraw(uint withdraw_amount) public {
        // Limit withdrawal amount
        require(withdraw_amount <= 100000000000000000);
        require(withdraw_amount <= 0.1 ether);
        require(
            address(this).balance >= withdraw_amount,
            "Insufficient balance in faucet for withdrawal request"
        );

        // Send the amount to the address that requested it
        payable(msg.sender).transfer(withdraw_amount);
        emit Withdrawal(msg.sender, withdraw_amount);
        // Some context
        // msg
        // tx
        // block
        // address
    }
}

八、Vyper

内容比较少 认为也不是主要编写合约代码,看一个solidity够了 就没看

九、智能合约安全

重入攻击

漏洞点:
line16 攻击方使用回调函数不断请求 然后维持的balances列表数据没有修改一直满足条件

修复:
1.内置transfer函数(内部限制了2300gas)
2.检查-生效-交互(把balances的修改放到调用之前)
3.sol代码中使用互斥锁

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
contract EtherStore {
    uint256 public withdrawalLimit = 1 ether;
    mapping(address => uint256) public lastWithdrawTime;
    mapping(address => uint256) public balances;

    function depositFunds() external payable {
        balances[msg.sender] += msg.value;
    }

    function withdrawFunds(uint256 _weiToWithdraw) public {
        require(balances[msg.sender] >= _weiToWithdraw);
        // limit the withdrawal
        require(_weiToWithdraw <= withdrawalLimit);
        // limit the time allowed to withdraw
        require(block.timestamp >= lastWithdrawTime[msg.sender] + 1 weeks);
        msg.sender.call{value: _weiToWithdraw}("");
        balances[msg.sender] -= _weiToWithdraw;
        lastWithdrawTime[msg.sender] = block.timestamp;
    }
}

整型溢出

漏洞点:
line11 整型上溢 increaseLockTime(2**256-userLockTime) 上溢为0 就可以取出ether了

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
contract TimeLock {
    mapping(address => uint256) public balances;
    mapping(address => uint256) public lockTime;

    function deposit() external payable {
        balances[msg.sender] += msg.value;
        lockTime[msg.sender] = block.timestamp + 1 weeks;
    }

    function increaseLockTime(uint256 _secondsToIncrease) public {
        lockTime[msg.sender] += _secondsToIncrease;
    }

    function withdraw() public {
        require(balances[msg.sender] > 0);
        require(block.timestamp > lockTime[msg.sender]);
        uint256 transferValue = balances[msg.sender];
        balances[msg.sender] = 0;
        payable(msg.sender).transfer(transferValue);
    }
}

漏洞点:
line14 15 整型下溢 0减去任何正整数都大于0

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// SPDX-License-Identifier: MIT
pragma solidity ^0.6.0;

contract Token {

  mapping(address => uint) balances;
  uint public totalSupply;

  constructor(uint _initialSupply) public {
    balances[msg.sender] = totalSupply = _initialSupply;
  }

  function transfer(address _to, uint _value) public returns (bool) {
    require(balances[msg.sender] - _value >= 0);
    balances[msg.sender] -= _value;
    balances[_to] += _value;
    return true;
  }

  function balanceOf(address _owner) public view returns (uint balance) {
    return balances[_owner];
  }
}

修复:
通常使用或构建安全算术运算的库合约来替代标准的算术加减

Unexpected Ether

  • selfdestruct指令可以将合约摧毁并将余额传入指定地址
  • 预先发送ether 合约地址通过 address = sha3(rlp.encode([account_address,transaction_nonce])) 计算 事先传入ether

漏洞点:
line 14 未预期的ether 传入非整数后 永远不可能等于10

修复:
漏洞来源于对this.balance的依赖,完全可以新增一个变量追踪充值数额,这样就可以避免攻击

 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
32
33
34
35
36
37
contract EtherGame {
    uint256 public payoutMileStone1 = 3 ether;
    uint256 public mileStone1Reward = 2 ether;
    uint256 public payoutMileStone2 = 5 ether;
    uint256 public mileStone2Reward = 3 ether;
    uint256 public finalMileStone = 10 ether;
    uint256 public finalReward = 5 ether;

    mapping(address => uint256) redeemableEther;

    // Users pay 0.5 ether. At specific milestones, credit their accounts.
    function play() external payable {
        require(msg.value == 0.5 ether); // each play is 0.5 ether
        uint256 currentBalance = address(this).balance + msg.value;
        // ensure no players after the game has finished
        require(currentBalance <= finalMileStone);
        // if at a milestone, credit the player's account
        if (currentBalance == payoutMileStone1) {
            redeemableEther[msg.sender] += mileStone1Reward;
        } else if (currentBalance == payoutMileStone2) {
            redeemableEther[msg.sender] += mileStone2Reward;
        } else if (currentBalance == finalMileStone) {
            redeemableEther[msg.sender] += finalReward;
        }
        return;
    }

    function claimReward() public {
        // ensure the game is complete
        require(address(this).balance == finalMileStone);
        // ensure there is a reward to give
        require(redeemableEther[msg.sender] > 0);
        uint256 transferValue = redeemableEther[msg.sender];
        redeemableEther[msg.sender] = 0;
        payable(msg.sender).transfer(transferValue);
    }
}

十、代币

ERC20、ERC721(NFT)

十一、预言机

预言机是一个可以回答以太坊外部问题的系统。
设置预言机的三种主要方式可以分为 请求于响应、发布与订阅、立即读取。
出于隐私考虑,可以在预言机上存储哈希而非原始数据。
发布与订阅预期改变的数据,预言机要么由链上智能合约轮询(耗费gas),要么由链外守护进程监视和更新(客户端的本地调用)。

十二、DAPP

IPFS、Swarm、Whisper

npm build
swarm --bzzapi http://localhost:8500 --recursive --defaultpath dist/index.html up dist/

ENS
.eth顶级域名、拍卖域名、设置子域名、使用公共解析器、解析Swarm

十三、EVM

基于栈的架构

1
2
3
4
5
6
# opcodes(middle)
solc -o BytecodeDir --opcodes Example.sol
# detailed(max)
solc -o BytecodeDir --asm Example.sol
# bin(min)
solc -o BytecodeDir --bin Example.sol

为尽量减少分析难度,编写了最简单的(没有汇入的可以说是错误的)水龙头代码,使用最新版本0.8.14(2022-05-21)solc编译获取字节码

1
2
3
4
5
6
7
pragma solidity 0.8.14;
contract Faucet {
    function withdraw(uint withdraw_amount) public {
      require(withdraw_amount <= 0.1 ether);
      payable(msg.sender).transfer(withdraw_amount);
    }
}

最初想尝试使用IDA-evm这个IDA插件进行分析,但是由于其仅支持python2,简单修复使其支持python3后发现并不能正常反编译出流程图

最后直接使用remix bytecode

代码分为代码段和数据段,代码段实际上是一个代码加载器,加载智能合约data中的数据,实际运行则是将数据段中数据移到0-len的位置,然后重入0开始运行,所以这是所有合约通用的加载器。

分析书上的版本编译器(0.6.x)生成的代码的时候发现许多愚蠢的指令 如下所示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
PUSH1 0x0
CALLDATASIZE
PUSH29 0x100000... 
SWAP1
DIV
PUSH4 0xffffffff
AND
DUP1
PUSH4 0x2e1a7d4d
EQ
PUSH1 0x41
JUMPI

这段代码就是实现一个函数选择器的功能,先calldataload 然后push29 再 swap 这不是浪费gas吗,一个取对应函数选择器的代码这么多指令有很大优化空间,相比起来最新的编译器生成的代码使用位移SHR(看了一下字节码是0x1c之前是未使用的所以可能是新加的指令 又看了一下EIP145提出的 创建时间2017年很早了)就高效得多

  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
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
{
	"functionDebugData": {},
	"generatedSources": [],
	"linkReferences": {},
	"object": "608060405234801561001057600080fd5b50610149806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c80632e1a7d4d14610030575b600080fd5b61004a600480360381019061004591906100e6565b61004c565b005b67016345785d8a000081111561006157600080fd5b3373ffffffffffffffffffffffffffffffffffffffff166108fc829081150290604051600060405180830381858888f193505050501580156100a7573d6000803e3d6000fd5b5050565b600080fd5b6000819050919050565b6100c3816100b0565b81146100ce57600080fd5b50565b6000813590506100e0816100ba565b92915050565b6000602082840312156100fc576100fb6100ab565b5b600061010a848285016100d1565b9150509291505056fea2646970667358221220e0ebfbb1f345e32e68dcacf4993ae16a9bd6a65a51698294e6c2094def89962564736f6c634300080e0033",
	"opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH2 0x149 DUP1 PUSH2 0x20 PUSH1 0x0 CODECOPY PUSH1 0x0 RETURN INVALID PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP PUSH1 0x4 CALLDATASIZE LT PUSH2 0x2B JUMPI PUSH1 0x0 CALLDATALOAD PUSH1 0xE0 SHR DUP1 PUSH4 0x2E1A7D4D EQ PUSH2 0x30 JUMPI JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH2 0x4A PUSH1 0x4 DUP1 CALLDATASIZE SUB DUP2 ADD SWAP1 PUSH2 0x45 SWAP2 SWAP1 PUSH2 0xE6 JUMP JUMPDEST PUSH2 0x4C JUMP JUMPDEST STOP JUMPDEST PUSH8 0x16345785D8A0000 DUP2 GT ISZERO PUSH2 0x61 JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST CALLER PUSH20 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF AND PUSH2 0x8FC DUP3 SWAP1 DUP2 ISZERO MUL SWAP1 PUSH1 0x40 MLOAD PUSH1 0x0 PUSH1 0x40 MLOAD DUP1 DUP4 SUB DUP2 DUP6 DUP9 DUP9 CALL SWAP4 POP POP POP POP ISZERO DUP1 ISZERO PUSH2 0xA7 JUMPI RETURNDATASIZE PUSH1 0x0 DUP1 RETURNDATACOPY RETURNDATASIZE PUSH1 0x0 REVERT JUMPDEST POP POP JUMP JUMPDEST PUSH1 0x0 DUP1 REVERT JUMPDEST PUSH1 0x0 DUP2 SWAP1 POP SWAP2 SWAP1 POP JUMP JUMPDEST PUSH2 0xC3 DUP2 PUSH2 0xB0 JUMP JUMPDEST DUP2 EQ PUSH2 0xCE JUMPI PUSH1 0x0 DUP1 REVERT JUMPDEST POP JUMP JUMPDEST PUSH1 0x0 DUP2 CALLDATALOAD SWAP1 POP PUSH2 0xE0 DUP2 PUSH2 0xBA JUMP JUMPDEST SWAP3 SWAP2 POP POP JUMP JUMPDEST PUSH1 0x0 PUSH1 0x20 DUP3 DUP5 SUB SLT ISZERO PUSH2 0xFC JUMPI PUSH2 0xFB PUSH2 0xAB JUMP JUMPDEST JUMPDEST PUSH1 0x0 PUSH2 0x10A DUP5 DUP3 DUP6 ADD PUSH2 0xD1 JUMP JUMPDEST SWAP2 POP POP SWAP3 SWAP2 POP POP JUMP INVALID LOG2 PUSH5 0x6970667358 0x22 SLT KECCAK256 0xE0 0xEB 0xFB 0xB1 RETURN GASLIMIT 0xE3 0x2E PUSH9 0xDCACF4993AE16A9BD6 0xA6 GAS MLOAD PUSH10 0x8294E6C2094DEF899625 PUSH5 0x736F6C6343 STOP ADDMOD 0xE STOP CALLER ",
	"sourceMap": "25:181:0:-:0;;;;;;;;;;;;;;;;;;;"
}
.code
  PUSH 80			contract Faucet {\r\n    funct...
  PUSH 40			contract Faucet {\r\n    funct...
  MSTORE 			contract Faucet {\r\n    funct...
  CALLVALUE 			contract Faucet {\r\n    funct...
  DUP1 			contract Faucet {\r\n    funct...
  ISZERO 			contract Faucet {\r\n    funct...
  PUSH [tag] 1			contract Faucet {\r\n    funct...
  JUMPI 			contract Faucet {\r\n    funct...
  PUSH 0			contract Faucet {\r\n    funct...
  DUP1 			contract Faucet {\r\n    funct...
  REVERT 			contract Faucet {\r\n    funct...
tag 1			contract Faucet {\r\n    funct...
  JUMPDEST 			contract Faucet {\r\n    funct...
  POP 			contract Faucet {\r\n    funct...
  PUSH #[$] 0000000000000000000000000000000000000000000000000000000000000000			contract Faucet {\r\n    funct...
  DUP1 			contract Faucet {\r\n    funct...
  PUSH [$] 0000000000000000000000000000000000000000000000000000000000000000			contract Faucet {\r\n    funct...
  PUSH 0			contract Faucet {\r\n    funct...
  CODECOPY 			contract Faucet {\r\n    funct...
  PUSH 0			contract Faucet {\r\n    funct...
  RETURN 			contract Faucet {\r\n    funct...
.data
  0:
    .code
      PUSH 80			contract Faucet {\r\n    funct...
      PUSH 40			contract Faucet {\r\n    funct...
      MSTORE 			contract Faucet {\r\n    funct...
      CALLVALUE 			contract Faucet {\r\n    funct...
      DUP1 			contract Faucet {\r\n    funct...
      ISZERO 			contract Faucet {\r\n    funct...
      PUSH [tag] 1			contract Faucet {\r\n    funct...
      JUMPI 			contract Faucet {\r\n    funct...
      PUSH 0			contract Faucet {\r\n    funct...
      DUP1 			contract Faucet {\r\n    funct...
      REVERT 			contract Faucet {\r\n    funct...
    tag 1			contract Faucet {\r\n    funct...
      JUMPDEST 			contract Faucet {\r\n    funct...
      POP 			contract Faucet {\r\n    funct...
      PUSH 4			contract Faucet {\r\n    funct...
      CALLDATASIZE 			contract Faucet {\r\n    funct...
      LT 			contract Faucet {\r\n    funct...
      PUSH [tag] 2			contract Faucet {\r\n    funct...
      JUMPI 			contract Faucet {\r\n    funct...
      PUSH 0			contract Faucet {\r\n    funct...
      CALLDATALOAD 			contract Faucet {\r\n    funct...
      PUSH E0			contract Faucet {\r\n    funct...
      SHR 			contract Faucet {\r\n    funct...
      DUP1 			contract Faucet {\r\n    funct...
      PUSH 2E1A7D4D			contract Faucet {\r\n    funct...
      EQ 			contract Faucet {\r\n    funct...
      PUSH [tag] 3			contract Faucet {\r\n    funct...
      JUMPI 			contract Faucet {\r\n    funct...
    tag 2			contract Faucet {\r\n    funct...
      JUMPDEST 			contract Faucet {\r\n    funct...
      PUSH 0			contract Faucet {\r\n    funct...
      DUP1 			contract Faucet {\r\n    funct...
      REVERT 			contract Faucet {\r\n    funct...
    tag 3			function withdraw(uint withdra...
      JUMPDEST 			function withdraw(uint withdra...
      PUSH [tag] 4			function withdraw(uint withdra...
      PUSH 4			function withdraw(uint withdra...
      DUP1 			function withdraw(uint withdra...
      CALLDATASIZE 			function withdraw(uint withdra...
      SUB 			function withdraw(uint withdra...
      DUP2 			function withdraw(uint withdra...
      ADD 			function withdraw(uint withdra...
      SWAP1 			function withdraw(uint withdra...
      PUSH [tag] 5			function withdraw(uint withdra...
      SWAP2 			function withdraw(uint withdra...
      SWAP1 			function withdraw(uint withdra...
      PUSH [tag] 6			function withdraw(uint withdra...
      JUMP 			function withdraw(uint withdra...
    tag 5			function withdraw(uint withdra...
      JUMPDEST 			function withdraw(uint withdra...
      PUSH [tag] 7			function withdraw(uint withdra...
      JUMP 			function withdraw(uint withdra...
    tag 4			function withdraw(uint withdra...
      JUMPDEST 			function withdraw(uint withdra...
      STOP 			function withdraw(uint withdra...
    tag 7			function withdraw(uint withdra...
      JUMPDEST 			function withdraw(uint withdra...
      PUSH 16345785D8A0000			0.1 ether
      DUP2 			withdraw_amount
      GT 			withdraw_amount <= 0.1 ether
      ISZERO 			withdraw_amount <= 0.1 ether
      PUSH [tag] 9			require(withdraw_amount <= 0.1...
      JUMPI 			require(withdraw_amount <= 0.1...
      PUSH 0			require(withdraw_amount <= 0.1...
      DUP1 			require(withdraw_amount <= 0.1...
      REVERT 			require(withdraw_amount <= 0.1...
    tag 9			require(withdraw_amount <= 0.1...
      JUMPDEST 			require(withdraw_amount <= 0.1...
      CALLER 			msg.sender
      PUSH FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF			payable(msg.sender).transfer
      AND 			payable(msg.sender).transfer
      PUSH 8FC			payable(msg.sender).transfer(w...
      DUP3 			withdraw_amount
      SWAP1 			payable(msg.sender).transfer(w...
      DUP2 			payable(msg.sender).transfer(w...
      ISZERO 			payable(msg.sender).transfer(w...
      MUL 			payable(msg.sender).transfer(w...
      SWAP1 			payable(msg.sender).transfer(w...
      PUSH 40			payable(msg.sender).transfer(w...
      MLOAD 			payable(msg.sender).transfer(w...
      PUSH 0			payable(msg.sender).transfer(w...
      PUSH 40			payable(msg.sender).transfer(w...
      MLOAD 			payable(msg.sender).transfer(w...
      DUP1 			payable(msg.sender).transfer(w...
      DUP4 			payable(msg.sender).transfer(w...
      SUB 			payable(msg.sender).transfer(w...
      DUP2 			payable(msg.sender).transfer(w...
      DUP6 			payable(msg.sender).transfer(w...
      DUP9 			payable(msg.sender).transfer(w...
      DUP9 			payable(msg.sender).transfer(w...
      CALL 			payable(msg.sender).transfer(w...
      SWAP4 			payable(msg.sender).transfer(w...
      POP 			payable(msg.sender).transfer(w...
      POP 			payable(msg.sender).transfer(w...
      POP 			payable(msg.sender).transfer(w...
      POP 			payable(msg.sender).transfer(w...
      ISZERO 			payable(msg.sender).transfer(w...
      DUP1 			payable(msg.sender).transfer(w...
      ISZERO 			payable(msg.sender).transfer(w...
      PUSH [tag] 11			payable(msg.sender).transfer(w...
      JUMPI 			payable(msg.sender).transfer(w...
      RETURNDATASIZE 			payable(msg.sender).transfer(w...
      PUSH 0			payable(msg.sender).transfer(w...
      DUP1 			payable(msg.sender).transfer(w...
      RETURNDATACOPY 			payable(msg.sender).transfer(w...
      RETURNDATASIZE 			payable(msg.sender).transfer(w...
      PUSH 0			payable(msg.sender).transfer(w...
      REVERT 			payable(msg.sender).transfer(w...
    tag 11			payable(msg.sender).transfer(w...
      JUMPDEST 			payable(msg.sender).transfer(w...
      POP 			payable(msg.sender).transfer(w...
      POP 			function withdraw(uint withdra...
      JUMP 			function withdraw(uint withdra...
    tag 13			public {\r\n      require(with...
      JUMPDEST 			public {\r\n      require(with...
      PUSH 0			\n
      DUP1 			)
      REVERT 			_amount);\r\n 
    tag 15			
      JUMPDEST 			
      PUSH 0			
      DUP2 			
      SWAP1 			
      POP 			
      SWAP2 			
      SWAP1 			
      POP 			
      JUMP 			
    tag 16			
      JUMPDEST 			
      PUSH [tag] 24			
      DUP2 			
      PUSH [tag] 15			
      JUMP 			
    tag 24			
      JUMPDEST 			
      DUP2 			
      EQ 			
      PUSH [tag] 25			
      JUMPI 			
      PUSH 0			
      DUP1 			
      REVERT 			
    tag 25			
      JUMPDEST 			
      POP 			
      JUMP 			
    tag 17			
      JUMPDEST 			
      PUSH 0			
      DUP2 			
      CALLDATALOAD 			
      SWAP1 			
      POP 			
      PUSH [tag] 27			
      DUP2 			
      PUSH [tag] 16			
      JUMP 			
    tag 27			
      JUMPDEST 			
      SWAP3 			
      SWAP2 			
      POP 			
      POP 			
      JUMP 			
    tag 6			
      JUMPDEST 			
      PUSH 0			
      PUSH 20			
      DUP3 			
      DUP5 			
      SUB 			
      SLT 			
      ISZERO 			
      PUSH [tag] 29			
      JUMPI 			
      PUSH [tag] 30			
      PUSH [tag] 13			
      JUMP 			
    tag 30			
      JUMPDEST 			
    tag 29			
      JUMPDEST 			
      PUSH 0			
      PUSH [tag] 31			
      DUP5 			
      DUP3 			
      DUP6 			
      ADD 			
      PUSH [tag] 17			
      JUMP 			
    tag 31			
      JUMPDEST 			
      SWAP2 			
      POP 			
      POP 			
      SWAP3 			
      SWAP2 			
      POP 			
      POP 			
      JUMP 			
    .data

十四、Consensus

PoS(惩罚内生 失去Ether) vs PoW(惩罚外生 失去电费)
Ethash:Ethereum PoW:依赖大型数据集(一个有向无环图 the DAG 难度线性增长 大型需频繁读取的数据结构 抗ASIC性 消费级GPU)的生成和分析
Casper:Ethereum PoS

Reference

Share on

ruokeqx
WRITTEN BY
ruokeqx