代码构成
以太坊智能合约代码由两部分构成,具体以如下代码为例来说明
contract C {
uint256 public a = 2;
function C() {
}
function d() {
a = 3;
}
function e() {
a = 1;
}
}
-
初始化代码
初始化代码只在创建智能合约的时候调用,只被调用一次初始化代码又由两部分构成: -
构造函数比如上面的C()函数function C() {}
-
全局变量初始化代码uint256 public a = 2;
-
-
接口代码
就是具体的实现函数,这个代码是智能合约非创建时间点的入口代码
function d() {
a = 3;
}
function e() {
a = 1;
}
汇编分析
初始化代码
- 全局变量a初始化代码
.code
PUSH 80 contract C {\n uint256 publ...
PUSH 40 contract C {\n uint256 publ...
MSTORE contract C {\n uint256 publ...
PUSH 2 2
PUSH 0 uint256 public a = 2
SSTORE uint256 public a = 2
-
返回接口代码的初始化代码检测value值,因为该合约构造函数不支持payable,所以如果value不为0,会revert
CALLVALUE function C() {\n }
DUP1 C {\n
ISZERO ac
PUSH [tag] 1 ac
JUMPI ac
PUSH 0 c
DUP1 b
REVERT t256 public
-
返回接口代码的初始化代码以下代码会返回该程序.data的代码,也就是接口代码的内容,核心代码是CODECOPY, 也就是通过CODECOPY将接口代码.data内容拷贝到memory,然后通过RETURN返回对应的memory的内容,也就是返回接口代码.data数据给系统代码
tag 1 ac
JUMPDEST ac
POP function C() {\n }
PUSH #[$] 0000000000000000000000000000000000000000000000000000000000000000 contract C {\n uint256 publ...
DUP1 contract C {\n uint256 publ...
PUSH [$] 0000000000000000000000000000000000000000000000000000000000000000 contract C {\n uint256 publ...
PUSH 0 contract C {\n uint256 publ...
CODECOPY contract C {\n uint256 publ...
PUSH 0 contract C {\n uint256 publ...
RETURN contract C {\n uint256 publ...
接口代码
我们知道,一个只能合约可能有很多合约,而客户端只通过input字段传入了调用函数的信息,因而智能合约需要有一个解释器,用来解释客户端想调用智能合约的哪一个接口(函数) ,传递了什么参数值. 因而接口代码也分为两部分
- 根据input数据查找函数
.data
0:
.code
PUSH 80 contract C {\n uint256 publ...
PUSH 40 contract C {\n uint256 publ...
MSTORE contract C {\n uint256 publ...
PUSH 4 contract C {\n uint256 publ...
CALLDATASIZE contract C {\n uint256 publ...
LT contract C {\n uint256 publ...
PUSH [tag] 1 contract C {\n uint256 publ...
JUMPI contract C {\n uint256 publ...
PUSH 0 contract C {\n uint256 publ...
CALLDATALOAD contract C {\n uint256 publ...
PUSH 100000000000000000000000000000000000000000000000000000000 contract C {\n uint256 publ...
SWAP1 contract C {\n uint256 publ...
DIV contract C {\n uint256 publ...
PUSH FFFFFFFF contract C {\n uint256 publ...
AND contract C {\n uint256 publ...
DUP1 contract C {\n uint256 publ...
PUSH DBE671F contract C {\n uint256 publ...
EQ contract C {\n uint256 publ...
PUSH [tag] 2 contract C {\n uint256 publ...
JUMPI contract C {\n uint256 publ...
DUP1 contract C {\n uint256 publ...
PUSH 8A054AC2 contract C {\n uint256 publ...
EQ contract C {\n uint256 publ...
PUSH [tag] 3 contract C {\n uint256 publ...
JUMPI contract C {\n uint256 publ...
DUP1 contract C {\n uint256 publ...
PUSH FFAE15BA contract C {\n uint256 publ...
EQ contract C {\n uint256 publ...
PUSH [tag] 4 contract C {\n uint256 publ...
JUMPI contract C {\n uint256 publ...
具体函数实现
tag 1 contract C {\n uint256 publ...
JUMPDEST contract C {\n uint256 publ...
PUSH 0 contract C {\n uint256 publ...
DUP1 contract C {\n uint256 publ...
REVERT contract C {\n uint256 publ...
tag 2 uint256 public a = 2
JUMPDEST uint256 public a = 2
CALLVALUE uint256 public a = 2
DUP1 C {\n
ISZERO ac
PUSH [tag] 5 ac
JUMPI ac
PUSH 0 c
DUP1 b
REVERT t256 public
tag 5 ac
JUMPDEST ac
POP uint256 public a = 2
PUSH [tag] 6 uint256 public a = 2
PUSH [tag] 7 uint256 public a = 2
JUMP uint256 public a = 2
tag 6 uint256 public a = 2
JUMPDEST uint256 public a = 2
PUSH 40 uint256 public a = 2
MLOAD uint256 public a = 2
DUP1 uint256 public a = 2
DUP3 uint256 public a = 2
DUP2 uint256 public a = 2
MSTORE uint256 public a = 2
PUSH 20 uint256 public a = 2
ADD uint256 public a = 2
SWAP2 uint256 public a = 2
POP uint256 public a = 2
POP uint256 public a = 2
PUSH 40 uint256 public a = 2
MLOAD uint256 public a = 2
DUP1 uint256 public a = 2
SWAP2 uint256 public a = 2
SUB uint256 public a = 2
SWAP1 uint256 public a = 2
RETURN uint256 public a = 2
tag 3 function d() {\n a = 3;...
JUMPDEST function d() {\n a = 3;...
CALLVALUE function d() {\n a = 3;...
DUP1 C {\n
ISZERO ac
PUSH [tag] 8 ac
JUMPI ac
PUSH 0 c
DUP1 b
REVERT t256 public
tag 8 ac
JUMPDEST ac
POP function d() {\n a = 3;...
PUSH [tag] 9 function d() {\n a = 3;...
PUSH [tag] 10 function d() {\n a = 3;...
JUMP function d() {\n a = 3;...
tag 9 function d() {\n a = 3;...
JUMPDEST function d() {\n a = 3;...
STOP function d() {\n a = 3;...
tag 4 function e() {\n a = 1;...
JUMPDEST function e() {\n a = 1;...
CALLVALUE function e() {\n a = 1;...
DUP1 C {\n
ISZERO ac
PUSH [tag] 11 ac
JUMPI ac
PUSH 0 c
DUP1 b
REVERT t256 public
tag 11 ac
JUMPDEST ac
POP function e() {\n a = 1;...
PUSH [tag] 12 function e() {\n a = 1;...
PUSH [tag] 13 function e() {\n a = 1;...
JUMP function e() {\n a = 1;...
tag 12 function e() {\n a = 1;...
JUMPDEST function e() {\n a = 1;...
STOP function e() {\n a = 1;...
tag 7 uint256 public a = 2
JUMPDEST uint256 public a = 2
PUSH 0 uint256 public a = 2
SLOAD uint256 public a = 2
DUP2 uint256 public a = 2
JUMP [out] uint256 public a = 2
tag 10 function d() {\n a = 3;...
JUMPDEST function d() {\n a = 3;...
PUSH 3 3
PUSH 0 a
DUP2 a = 3
SWAP1 a = 3
SSTORE a = 3
POP a = 3
JUMP [out] function d() {\n a = 3;...
tag 13 function e() {\n a = 1;...
JUMPDEST function e() {\n a = 1;...
PUSH 1 1
PUSH 0 a
DUP2 a = 1
SWAP1 a = 1
SSTORE a = 1
POP a = 1
JUMP [out] function e() {\n a = 1;...
.data
初始化代码执行源码分析
func (evm *EVM) Create(caller ContractRef, code []byte, gas uint64, value *big.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) {
….
contract := NewContract(caller, AccountRef(contractAddr), value, gas)
//初始化code为全部的数据(包括code,data数据)
contract.SetCallCode(&contractAddr, crypto.Keccak256Hash(code), code)
if evm.vmConfig.NoRecursion && evm.depth > 0 {
return nil, contractAddr, gas, nil
}
if evm.vmConfig.Debug && evm.depth == 0 {
evm.vmConfig.Tracer.CaptureStart(caller.Address(), contractAddr, true, code, gas, value)
}
start := time.Now()
//这里会执行初始化代码,返回值是接口代码数据
ret, err = run(evm, contract, nil)
// check whether the max code size has been exceeded
maxCodeSizeExceeded := evm.ChainConfig().IsEIP158(evm.BlockNumber) && len(ret) > params.MaxCodeSize
// if the contract creation ran successfully and no errors were returned
// calculate the gas required to store the code. If the code could not
// be stored due to not enough gas set an error and let it be handled
// by the error checking condition below.
if err == nil && !maxCodeSizeExceeded {
createDataGas := uint64(len(ret)) * params.CreateDataGas
if contract.UseGas(createDataGas) {
//将contract的code更新为接口代码
evm.StateDB.SetCode(contractAddr, ret)
} else {
err = ErrCodeStoreOutOfGas
}
}
return ret, contractAddr, contract.Gas, err
}
/********************************
* 本文来自CSDN博主"爱踢门"
******************************************/