Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
whqwjb
go-ethereum
提交
76069eef
G
go-ethereum
项目概览
whqwjb
/
go-ethereum
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
go-ethereum
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
76069eef
编写于
8月 16, 2017
作者:
P
Péter Szilágyi
提交者:
GitHub
8月 16, 2017
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #14978 from karalabe/metropolis-staticcall
core/vm: implement metropolis static call opcode
上级
30402430
3df7142b
变更
7
隐藏空白更改
内联
并排
Showing
7 changed file
with
168 addition
and
22 deletion
+168
-22
core/vm/evm.go
core/vm/evm.go
+61
-19
core/vm/gas_table.go
core/vm/gas_table.go
+27
-0
core/vm/instructions.go
core/vm/instructions.go
+32
-1
core/vm/interpreter.go
core/vm/interpreter.go
+15
-0
core/vm/jump_table.go
core/vm/jump_table.go
+23
-2
core/vm/memory_table.go
core/vm/memory_table.go
+7
-0
core/vm/opcodes.go
core/vm/opcodes.go
+3
-0
未找到文件。
core/vm/evm.go
浏览文件 @
76069eef
...
...
@@ -123,19 +123,20 @@ func (evm *EVM) Cancel() {
atomic
.
StoreInt32
(
&
evm
.
abort
,
1
)
}
// Call executes the contract associated with the addr with the given input as parameters. It also handles any
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
// case of an execution error or failed value transfer.
// Call executes the contract associated with the addr with the given input as
// parameters. It also handles any necessary value transfer required and takes
// the necessary steps to create accounts and reverses the state in case of an
// execution error or failed value transfer.
func
(
evm
*
EVM
)
Call
(
caller
ContractRef
,
addr
common
.
Address
,
input
[]
byte
,
gas
uint64
,
value
*
big
.
Int
)
(
ret
[]
byte
,
leftOverGas
uint64
,
err
error
)
{
if
evm
.
vmConfig
.
NoRecursion
&&
evm
.
depth
>
0
{
return
nil
,
gas
,
nil
}
// Depth check execution. Fail if we're trying to execute above the
// limit.
// Fail if we're trying to execute above the call depth limit
if
evm
.
depth
>
int
(
params
.
CallCreateDepth
)
{
return
nil
,
gas
,
ErrDepth
}
// Fail if we're trying to transfer more than the available balance
if
!
evm
.
Context
.
CanTransfer
(
evm
.
StateDB
,
caller
.
Address
(),
value
)
{
return
nil
,
gas
,
ErrInsufficientBalance
}
...
...
@@ -173,21 +174,23 @@ func (evm *EVM) Call(caller ContractRef, addr common.Address, input []byte, gas
return
ret
,
contract
.
Gas
,
err
}
// CallCode executes the contract associated with the addr with the given input as parameters. It also handles any
// necessary value transfer required and takes the necessary steps to create accounts and reverses the state in
// case of an execution error or failed value transfer.
// CallCode executes the contract associated with the addr with the given input
// as parameters. It also handles any necessary value transfer required and takes
// the necessary steps to create accounts and reverses the state in case of an
// execution error or failed value transfer.
//
// CallCode differs from Call in the sense that it executes the given address' code with the caller as context.
// CallCode differs from Call in the sense that it executes the given address'
// code with the caller as context.
func
(
evm
*
EVM
)
CallCode
(
caller
ContractRef
,
addr
common
.
Address
,
input
[]
byte
,
gas
uint64
,
value
*
big
.
Int
)
(
ret
[]
byte
,
leftOverGas
uint64
,
err
error
)
{
if
evm
.
vmConfig
.
NoRecursion
&&
evm
.
depth
>
0
{
return
nil
,
gas
,
nil
}
// Depth check execution. Fail if we're trying to execute above the
// limit.
// Fail if we're trying to execute above the call depth limit
if
evm
.
depth
>
int
(
params
.
CallCreateDepth
)
{
return
nil
,
gas
,
ErrDepth
}
// Fail if we're trying to transfer more than the available balance
if
!
evm
.
CanTransfer
(
evm
.
StateDB
,
caller
.
Address
(),
value
)
{
return
nil
,
gas
,
ErrInsufficientBalance
}
...
...
@@ -211,18 +214,16 @@ func (evm *EVM) CallCode(caller ContractRef, addr common.Address, input []byte,
return
ret
,
contract
.
Gas
,
err
}
// DelegateCall executes the contract associated with the addr with the given input
as parameters.
// It reverses the state in case of an execution error.
// DelegateCall executes the contract associated with the addr with the given input
//
as parameters.
It reverses the state in case of an execution error.
//
// DelegateCall differs from CallCode in the sense that it executes the given address'
code with the caller as context
// and the caller is set to the caller of the caller.
// DelegateCall differs from CallCode in the sense that it executes the given address'
//
code with the caller as context
and the caller is set to the caller of the caller.
func
(
evm
*
EVM
)
DelegateCall
(
caller
ContractRef
,
addr
common
.
Address
,
input
[]
byte
,
gas
uint64
)
(
ret
[]
byte
,
leftOverGas
uint64
,
err
error
)
{
if
evm
.
vmConfig
.
NoRecursion
&&
evm
.
depth
>
0
{
return
nil
,
gas
,
nil
}
// Depth check execution. Fail if we're trying to execute above the
// limit.
// Fail if we're trying to execute above the call depth limit
if
evm
.
depth
>
int
(
params
.
CallCreateDepth
)
{
return
nil
,
gas
,
ErrDepth
}
...
...
@@ -232,7 +233,7 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
to
=
AccountRef
(
caller
.
Address
())
)
// I
i
nitialise a new contract and make initialise the delegate values
// Initialise a new contract and make initialise the delegate values
contract
:=
NewContract
(
caller
,
to
,
nil
,
gas
)
.
AsDelegate
()
contract
.
SetCallCode
(
&
addr
,
evm
.
StateDB
.
GetCodeHash
(
addr
),
evm
.
StateDB
.
GetCode
(
addr
))
...
...
@@ -245,6 +246,47 @@ func (evm *EVM) DelegateCall(caller ContractRef, addr common.Address, input []by
return
ret
,
contract
.
Gas
,
err
}
// StaticCall executes the contract associated with the addr with the given input
// as parameters while disallowing any modifications to the state during the call.
// Opcodes that attempt to perform such modifications will result in exceptions
// instead of performing the modifications.
func
(
evm
*
EVM
)
StaticCall
(
caller
ContractRef
,
addr
common
.
Address
,
input
[]
byte
,
gas
uint64
)
(
ret
[]
byte
,
leftOverGas
uint64
,
err
error
)
{
if
evm
.
vmConfig
.
NoRecursion
&&
evm
.
depth
>
0
{
return
nil
,
gas
,
nil
}
// Fail if we're trying to execute above the call depth limit
if
evm
.
depth
>
int
(
params
.
CallCreateDepth
)
{
return
nil
,
gas
,
ErrDepth
}
// Make sure the readonly is only set if we aren't in readonly yet
// this makes also sure that the readonly flag isn't removed for
// child calls.
if
!
evm
.
interpreter
.
readonly
{
evm
.
interpreter
.
readonly
=
true
defer
func
()
{
evm
.
interpreter
.
readonly
=
false
}()
}
var
(
to
=
AccountRef
(
addr
)
snapshot
=
evm
.
StateDB
.
Snapshot
()
)
// Initialise a new contract and set the code that is to be used by the
// EVM. The contract is a scoped environment for this execution context
// only.
contract
:=
NewContract
(
caller
,
to
,
new
(
big
.
Int
),
gas
)
contract
.
SetCallCode
(
&
addr
,
evm
.
StateDB
.
GetCodeHash
(
addr
),
evm
.
StateDB
.
GetCode
(
addr
))
// When an error was returned by the EVM or when setting the creation code
// above we revert to the snapshot and consume any gas remaining. Additionally
// when we're in Homestead this also counts for code storage gas errors.
ret
,
err
=
run
(
evm
,
snapshot
,
contract
,
input
)
if
err
!=
nil
{
contract
.
UseGas
(
contract
.
Gas
)
evm
.
StateDB
.
RevertToSnapshot
(
snapshot
)
}
return
ret
,
contract
.
Gas
,
err
}
// Create creates a new contract using code as deployment code.
func
(
evm
*
EVM
)
Create
(
caller
ContractRef
,
code
[]
byte
,
gas
uint64
,
value
*
big
.
Int
)
(
ret
[]
byte
,
contractAddr
common
.
Address
,
leftOverGas
uint64
,
err
error
)
{
if
evm
.
vmConfig
.
NoRecursion
&&
evm
.
depth
>
0
{
...
...
core/vm/gas_table.go
浏览文件 @
76069eef
...
...
@@ -423,6 +423,33 @@ func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *St
return
gas
,
nil
}
func
gasStaticCall
(
gt
params
.
GasTable
,
evm
*
EVM
,
contract
*
Contract
,
stack
*
Stack
,
mem
*
Memory
,
memorySize
uint64
)
(
uint64
,
error
)
{
gas
,
err
:=
memoryGasCost
(
mem
,
memorySize
)
if
err
!=
nil
{
return
0
,
err
}
var
overflow
bool
if
gas
,
overflow
=
math
.
SafeAdd
(
gas
,
gt
.
Calls
);
overflow
{
return
0
,
errGasUintOverflow
}
cg
,
err
:=
callGas
(
gt
,
contract
.
Gas
,
gas
,
stack
.
Back
(
0
))
if
err
!=
nil
{
return
0
,
err
}
// Replace the stack item with the new gas calculation. This means that
// either the original item is left on the stack or the item is replaced by:
// (availableGas - gas) * 63 / 64
// We replace the stack item so that it's available when the opCall instruction is
// called.
stack
.
data
[
stack
.
len
()
-
1
]
=
new
(
big
.
Int
)
.
SetUint64
(
cg
)
if
gas
,
overflow
=
math
.
SafeAdd
(
gas
,
cg
);
overflow
{
return
0
,
errGasUintOverflow
}
return
gas
,
nil
}
func
gasPush
(
gt
params
.
GasTable
,
evm
*
EVM
,
contract
*
Contract
,
stack
*
Stack
,
mem
*
Memory
,
memorySize
uint64
)
(
uint64
,
error
)
{
return
GasFastestStep
,
nil
}
...
...
core/vm/instructions.go
浏览文件 @
76069eef
...
...
@@ -17,6 +17,7 @@
package
vm
import
(
"errors"
"fmt"
"math/big"
...
...
@@ -28,7 +29,8 @@ import (
)
var
(
bigZero
=
new
(
big
.
Int
)
bigZero
=
new
(
big
.
Int
)
errWriteProtection
=
errors
.
New
(
"evm: write protection"
)
)
func
opAdd
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
...
...
@@ -656,6 +658,35 @@ func opDelegateCall(pc *uint64, evm *EVM, contract *Contract, memory *Memory, st
return
ret
,
nil
}
func
opStaticCall
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
// pop gas
gas
:=
stack
.
pop
()
.
Uint64
()
// pop address
addr
:=
stack
.
pop
()
// pop input size and offset
inOffset
,
inSize
:=
stack
.
pop
(),
stack
.
pop
()
// pop return size and offset
retOffset
,
retSize
:=
stack
.
pop
(),
stack
.
pop
()
address
:=
common
.
BigToAddress
(
addr
)
// Get the arguments from the memory
args
:=
memory
.
Get
(
inOffset
.
Int64
(),
inSize
.
Int64
())
ret
,
returnGas
,
err
:=
evm
.
StaticCall
(
contract
,
address
,
args
,
gas
)
if
err
!=
nil
{
stack
.
push
(
new
(
big
.
Int
))
}
else
{
stack
.
push
(
big
.
NewInt
(
1
))
memory
.
Set
(
retOffset
.
Uint64
(),
retSize
.
Uint64
(),
ret
)
}
contract
.
Gas
+=
returnGas
evm
.
interpreter
.
intPool
.
put
(
addr
,
inOffset
,
inSize
,
retOffset
,
retSize
)
return
ret
,
nil
}
func
opReturn
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
offset
,
size
:=
stack
.
pop
(),
stack
.
pop
()
ret
:=
memory
.
GetPtr
(
offset
.
Int64
(),
size
.
Int64
())
...
...
core/vm/interpreter.go
浏览文件 @
76069eef
...
...
@@ -69,6 +69,8 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
// we'll set the default jump table.
if
!
cfg
.
JumpTable
[
STOP
]
.
valid
{
switch
{
case
evm
.
ChainConfig
()
.
IsMetropolis
(
evm
.
BlockNumber
)
:
cfg
.
JumpTable
=
metropolisInstructionSet
case
evm
.
ChainConfig
()
.
IsHomestead
(
evm
.
BlockNumber
)
:
cfg
.
JumpTable
=
homesteadInstructionSet
default
:
...
...
@@ -85,6 +87,18 @@ func NewInterpreter(evm *EVM, cfg Config) *Interpreter {
}
func
(
in
*
Interpreter
)
enforceRestrictions
(
op
OpCode
,
operation
operation
,
stack
*
Stack
)
error
{
if
in
.
evm
.
chainRules
.
IsMetropolis
{
if
in
.
readonly
{
// If the interpreter is operating in readonly mode, make sure no
// state-modifying operation is performed. The 3rd stack item
// for a call operation is the value. Transfering value from one
// account to the others means the state is modified and should also
// return with an error.
if
operation
.
writes
||
(
op
==
CALL
&&
stack
.
Back
(
2
)
.
BitLen
()
>
0
)
{
return
errWriteProtection
}
}
}
return
nil
}
...
...
@@ -95,6 +109,7 @@ func (in *Interpreter) enforceRestrictions(op OpCode, operation operation, stack
// considered a revert-and-consume-all-gas operation. No error specific checks
// should be handled to reduce complexity and errors further down the in.
func
(
in
*
Interpreter
)
Run
(
snapshot
int
,
contract
*
Contract
,
input
[]
byte
)
(
ret
[]
byte
,
err
error
)
{
// Increment the call depth which is restricted to 1024
in
.
evm
.
depth
++
defer
func
()
{
in
.
evm
.
depth
--
}()
...
...
core/vm/jump_table.go
浏览文件 @
76069eef
...
...
@@ -56,10 +56,26 @@ type operation struct {
}
var
(
frontierInstructionSet
=
NewFrontierInstructionSet
()
homesteadInstructionSet
=
NewHomesteadInstructionSet
()
frontierInstructionSet
=
NewFrontierInstructionSet
()
homesteadInstructionSet
=
NewHomesteadInstructionSet
()
metropolisInstructionSet
=
NewMetropolisInstructionSet
()
)
// NewMetropolisInstructionSet returns the frontier, homestead and
// metropolis instructions.
func
NewMetropolisInstructionSet
()
[
256
]
operation
{
// instructions that can be executed during the homestead phase.
instructionSet
:=
NewHomesteadInstructionSet
()
instructionSet
[
STATICCALL
]
=
operation
{
execute
:
opStaticCall
,
gasCost
:
gasStaticCall
,
validateStack
:
makeStackFunc
(
6
,
1
),
memorySize
:
memoryStaticCall
,
valid
:
true
,
}
return
instructionSet
}
// NewHomesteadInstructionSet returns the frontier and homestead
// instructions that can be executed during the homestead phase.
func
NewHomesteadInstructionSet
()
[
256
]
operation
{
...
...
@@ -810,6 +826,7 @@ func NewFrontierInstructionSet() [256]operation {
validateStack
:
makeStackFunc
(
2
,
0
),
memorySize
:
memoryLog
,
valid
:
true
,
writes
:
true
,
},
LOG1
:
{
execute
:
makeLog
(
1
),
...
...
@@ -817,6 +834,7 @@ func NewFrontierInstructionSet() [256]operation {
validateStack
:
makeStackFunc
(
3
,
0
),
memorySize
:
memoryLog
,
valid
:
true
,
writes
:
true
,
},
LOG2
:
{
execute
:
makeLog
(
2
),
...
...
@@ -824,6 +842,7 @@ func NewFrontierInstructionSet() [256]operation {
validateStack
:
makeStackFunc
(
4
,
0
),
memorySize
:
memoryLog
,
valid
:
true
,
writes
:
true
,
},
LOG3
:
{
execute
:
makeLog
(
3
),
...
...
@@ -831,6 +850,7 @@ func NewFrontierInstructionSet() [256]operation {
validateStack
:
makeStackFunc
(
5
,
0
),
memorySize
:
memoryLog
,
valid
:
true
,
writes
:
true
,
},
LOG4
:
{
execute
:
makeLog
(
4
),
...
...
@@ -838,6 +858,7 @@ func NewFrontierInstructionSet() [256]operation {
validateStack
:
makeStackFunc
(
6
,
0
),
memorySize
:
memoryLog
,
valid
:
true
,
writes
:
true
,
},
CREATE
:
{
execute
:
opCreate
,
...
...
core/vm/memory_table.go
浏览文件 @
76069eef
...
...
@@ -74,6 +74,13 @@ func memoryDelegateCall(stack *Stack) *big.Int {
return
math
.
BigMax
(
x
,
y
)
}
func
memoryStaticCall
(
stack
*
Stack
)
*
big
.
Int
{
x
:=
calcMemSize
(
stack
.
Back
(
4
),
stack
.
Back
(
5
))
y
:=
calcMemSize
(
stack
.
Back
(
2
),
stack
.
Back
(
3
))
return
math
.
BigMax
(
x
,
y
)
}
func
memoryReturn
(
stack
*
Stack
)
*
big
.
Int
{
return
calcMemSize
(
stack
.
Back
(
0
),
stack
.
Back
(
1
))
}
...
...
core/vm/opcodes.go
浏览文件 @
76069eef
...
...
@@ -201,6 +201,7 @@ const (
CALLCODE
RETURN
DELEGATECALL
STATICCALL
=
0xfa
SELFDESTRUCT
=
0xff
)
...
...
@@ -355,6 +356,7 @@ var opCodeToString = map[OpCode]string{
RETURN
:
"RETURN"
,
CALLCODE
:
"CALLCODE"
,
DELEGATECALL
:
"DELEGATECALL"
,
STATICCALL
:
"STATICCALL"
,
SELFDESTRUCT
:
"SELFDESTRUCT"
,
PUSH
:
"PUSH"
,
...
...
@@ -405,6 +407,7 @@ var stringToOp = map[string]OpCode{
"CALLDATASIZE"
:
CALLDATASIZE
,
"CALLDATACOPY"
:
CALLDATACOPY
,
"DELEGATECALL"
:
DELEGATECALL
,
"STATICCALL"
:
STATICCALL
,
"CODESIZE"
:
CODESIZE
,
"CODECOPY"
:
CODECOPY
,
"GASPRICE"
:
GASPRICE
,
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录