Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
G
Geth-Modification
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
张蕾
Geth-Modification
Commits
0b978f91
Commit
0b978f91
authored
Aug 16, 2017
by
Péter Szilágyi
Committed by
GitHub
Aug 16, 2017
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #14981 from karalabe/metropolis-returndata
core/vm: implement RETURNDATA metropolis opcodes
parents
76069eef
64d199ed
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
280 additions
and
195 deletions
+280
-195
evm.go
core/vm/evm.go
+3
-3
gas_table.go
core/vm/gas_table.go
+27
-1
instructions.go
core/vm/instructions.go
+52
-26
interpreter.go
core/vm/interpreter.go
+11
-6
jump_table.go
core/vm/jump_table.go
+25
-5
memory.go
core/vm/memory.go
+0
-1
memory_table.go
core/vm/memory_table.go
+5
-1
opcodes.go
core/vm/opcodes.go
+156
-151
testdata
tests/testdata
+1
-1
No files found.
core/vm/evm.go
View file @
0b978f91
...
...
@@ -261,9 +261,9 @@ func (evm *EVM) StaticCall(caller ContractRef, addr common.Address, input []byte
// 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
.
read
o
nly
{
evm
.
interpreter
.
read
o
nly
=
true
defer
func
()
{
evm
.
interpreter
.
read
o
nly
=
false
}()
if
!
evm
.
interpreter
.
read
O
nly
{
evm
.
interpreter
.
read
O
nly
=
true
defer
func
()
{
evm
.
interpreter
.
read
O
nly
=
false
}()
}
var
(
...
...
core/vm/gas_table.go
View file @
0b978f91
...
...
@@ -65,7 +65,33 @@ func constGasFunc(gas uint64) gasFunc {
}
}
func
gasCalldataCopy
(
gt
params
.
GasTable
,
evm
*
EVM
,
contract
*
Contract
,
stack
*
Stack
,
mem
*
Memory
,
memorySize
uint64
)
(
uint64
,
error
)
{
func
gasCallDataCopy
(
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
,
GasFastestStep
);
overflow
{
return
0
,
errGasUintOverflow
}
words
,
overflow
:=
bigUint64
(
stack
.
Back
(
2
))
if
overflow
{
return
0
,
errGasUintOverflow
}
if
words
,
overflow
=
math
.
SafeMul
(
toWordSize
(
words
),
params
.
CopyGas
);
overflow
{
return
0
,
errGasUintOverflow
}
if
gas
,
overflow
=
math
.
SafeAdd
(
gas
,
words
);
overflow
{
return
0
,
errGasUintOverflow
}
return
gas
,
nil
}
func
gasReturnDataCopy
(
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
...
...
core/vm/instructions.go
View file @
0b978f91
...
...
@@ -31,6 +31,7 @@ import (
var
(
bigZero
=
new
(
big
.
Int
)
errWriteProtection
=
errors
.
New
(
"evm: write protection"
)
errReturnDataOutOfBounds
=
errors
.
New
(
"evm: return data out of bounds"
)
)
func
opAdd
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
...
...
@@ -242,6 +243,7 @@ func opAnd(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stac
evm
.
interpreter
.
intPool
.
put
(
y
)
return
nil
,
nil
}
func
opOr
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
x
,
y
:=
stack
.
pop
(),
stack
.
pop
()
stack
.
push
(
x
.
Or
(
x
,
y
))
...
...
@@ -249,6 +251,7 @@ func opOr(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Stack
evm
.
interpreter
.
intPool
.
put
(
y
)
return
nil
,
nil
}
func
opXor
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
x
,
y
:=
stack
.
pop
(),
stack
.
pop
()
stack
.
push
(
x
.
Xor
(
x
,
y
))
...
...
@@ -268,6 +271,7 @@ func opByte(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
evm
.
interpreter
.
intPool
.
put
(
th
)
return
nil
,
nil
}
func
opAddmod
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
x
,
y
,
z
:=
stack
.
pop
(),
stack
.
pop
(),
stack
.
pop
()
if
z
.
Cmp
(
bigZero
)
>
0
{
...
...
@@ -281,6 +285,7 @@ func opAddmod(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *S
evm
.
interpreter
.
intPool
.
put
(
y
,
z
)
return
nil
,
nil
}
func
opMulmod
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
x
,
y
,
z
:=
stack
.
pop
(),
stack
.
pop
(),
stack
.
pop
()
if
z
.
Cmp
(
bigZero
)
>
0
{
...
...
@@ -338,25 +343,47 @@ func opCallValue(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
return
nil
,
nil
}
func
opCall
d
ataLoad
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
func
opCall
D
ataLoad
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
stack
.
push
(
new
(
big
.
Int
)
.
SetBytes
(
getDataBig
(
contract
.
Input
,
stack
.
pop
(),
big32
)))
return
nil
,
nil
}
func
opCall
d
ataSize
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
func
opCall
D
ataSize
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
stack
.
push
(
evm
.
interpreter
.
intPool
.
get
()
.
SetInt64
(
int64
(
len
(
contract
.
Input
))))
return
nil
,
nil
}
func
opCalldataCopy
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
func
opCallDataCopy
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
var
(
memOffset
=
stack
.
pop
()
dataOffset
=
stack
.
pop
()
length
=
stack
.
pop
()
)
memory
.
Set
(
memOffset
.
Uint64
(),
length
.
Uint64
(),
getDataBig
(
contract
.
Input
,
dataOffset
,
length
))
evm
.
interpreter
.
intPool
.
put
(
memOffset
,
dataOffset
,
length
)
return
nil
,
nil
}
func
opReturnDataSize
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
stack
.
push
(
evm
.
interpreter
.
intPool
.
get
()
.
SetUint64
(
uint64
(
len
(
evm
.
interpreter
.
returnData
))))
return
nil
,
nil
}
func
opReturnDataCopy
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
var
(
m
Off
=
stack
.
pop
()
cOff
=
stack
.
pop
()
l
=
stack
.
pop
()
m
emOffset
=
stack
.
pop
()
dataOffset
=
stack
.
pop
()
l
ength
=
stack
.
pop
()
)
memory
.
Set
(
mOff
.
Uint64
(),
l
.
Uint64
(),
getDataBig
(
contract
.
Input
,
cOff
,
l
))
defer
evm
.
interpreter
.
intPool
.
put
(
memOffset
,
dataOffset
,
length
)
end
:=
new
(
big
.
Int
)
.
Add
(
dataOffset
,
length
)
if
end
.
BitLen
()
>
64
||
uint64
(
len
(
evm
.
interpreter
.
returnData
))
<
end
.
Uint64
()
{
return
nil
,
errReturnDataOutOfBounds
}
memory
.
Set
(
memOffset
.
Uint64
(),
length
.
Uint64
(),
evm
.
interpreter
.
returnData
[
dataOffset
.
Uint64
()
:
end
.
Uint64
()])
evm
.
interpreter
.
intPool
.
put
(
mOff
,
cOff
,
l
)
return
nil
,
nil
}
...
...
@@ -378,31 +405,28 @@ func opCodeSize(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack
func
opCodeCopy
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
var
(
m
Off
=
stack
.
pop
()
c
Off
=
stack
.
pop
()
l
=
stack
.
pop
()
m
emOffset
=
stack
.
pop
()
c
odeOffset
=
stack
.
pop
()
l
ength
=
stack
.
pop
()
)
codeCopy
:=
getDataBig
(
contract
.
Code
,
cOff
,
l
)
codeCopy
:=
getDataBig
(
contract
.
Code
,
codeOffset
,
length
)
memory
.
Set
(
memOffset
.
Uint64
(),
length
.
Uint64
(),
codeCopy
)
memory
.
Set
(
mOff
.
Uint64
(),
l
.
Uint64
(),
codeCopy
)
evm
.
interpreter
.
intPool
.
put
(
mOff
,
cOff
,
l
)
evm
.
interpreter
.
intPool
.
put
(
memOffset
,
codeOffset
,
length
)
return
nil
,
nil
}
func
opExtCodeCopy
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
var
(
addr
=
common
.
BigToAddress
(
stack
.
pop
())
m
Off
=
stack
.
pop
()
c
Off
=
stack
.
pop
()
l
=
stack
.
pop
()
m
emOffset
=
stack
.
pop
()
c
odeOffset
=
stack
.
pop
()
l
ength
=
stack
.
pop
()
)
codeCopy
:=
getDataBig
(
evm
.
StateDB
.
GetCode
(
addr
),
cOff
,
l
)
memory
.
Set
(
mOff
.
Uint64
(),
l
.
Uint64
(),
codeCopy
)
evm
.
interpreter
.
intPool
.
put
(
mOff
,
cOff
,
l
)
codeCopy
:=
getDataBig
(
evm
.
StateDB
.
GetCode
(
addr
),
codeOffset
,
length
)
memory
.
Set
(
memOffset
.
Uint64
(),
length
.
Uint64
(),
codeCopy
)
evm
.
interpreter
.
intPool
.
put
(
memOffset
,
codeOffset
,
length
)
return
nil
,
nil
}
...
...
@@ -507,6 +531,7 @@ func opJump(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *Sta
evm
.
interpreter
.
intPool
.
put
(
pos
)
return
nil
,
nil
}
func
opJumpi
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
pos
,
cond
:=
stack
.
pop
(),
stack
.
pop
()
if
cond
.
Sign
()
!=
0
{
...
...
@@ -522,6 +547,7 @@ func opJumpi(pc *uint64, evm *EVM, contract *Contract, memory *Memory, stack *St
evm
.
interpreter
.
intPool
.
put
(
pos
,
cond
)
return
nil
,
nil
}
func
opJumpdest
(
pc
*
uint64
,
evm
*
EVM
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
([]
byte
,
error
)
{
return
nil
,
nil
}
...
...
core/vm/interpreter.go
View file @
0b978f91
...
...
@@ -59,7 +59,8 @@ type Interpreter struct {
gasTable
params
.
GasTable
intPool
*
intPool
readonly
bool
readOnly
bool
// Whether to throw on stateful modifications
returnData
[]
byte
// Last CALL's return data for subsequent reuse
}
// NewInterpreter returns a new instance of the Interpreter.
...
...
@@ -88,7 +89,7 @@ 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
.
read
o
nly
{
if
in
.
read
O
nly
{
// 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
...
...
@@ -113,6 +114,10 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
in
.
evm
.
depth
++
defer
func
()
{
in
.
evm
.
depth
--
}()
// Reset the previous call's return data. It's unimportant to preserve the old buffer
// as every returning call will return new data anyway.
in
.
returnData
=
nil
// Don't bother with the execution if there's no code.
if
len
(
contract
.
Code
)
==
0
{
return
nil
,
nil
...
...
@@ -213,10 +218,10 @@ func (in *Interpreter) Run(snapshot int, contract *Contract, input []byte) (ret
case
!
operation
.
jumps
:
pc
++
}
// if the operation
returned a value make sure that is also set
//
the last return data
.
if
res
!=
nil
{
mem
.
lastReturn
=
ret
// if the operation
clears the return data (e.g. it has returning data)
//
set the last return to the result of the operation
.
if
operation
.
returns
{
in
.
returnData
=
res
}
}
return
nil
,
nil
...
...
core/vm/jump_table.go
View file @
0b978f91
...
...
@@ -53,6 +53,8 @@ type operation struct {
valid
bool
// reverts determined whether the operation reverts state
reverts
bool
// returns determines whether the opertions sets the return data
returns
bool
}
var
(
...
...
@@ -72,6 +74,20 @@ func NewMetropolisInstructionSet() [256]operation {
validateStack
:
makeStackFunc
(
6
,
1
),
memorySize
:
memoryStaticCall
,
valid
:
true
,
returns
:
true
,
}
instructionSet
[
RETURNDATASIZE
]
=
operation
{
execute
:
opReturnDataSize
,
gasCost
:
constGasFunc
(
GasQuickStep
),
validateStack
:
makeStackFunc
(
0
,
1
),
valid
:
true
,
}
instructionSet
[
RETURNDATACOPY
]
=
operation
{
execute
:
opReturnDataCopy
,
gasCost
:
gasReturnDataCopy
,
validateStack
:
makeStackFunc
(
3
,
0
),
memorySize
:
memoryReturnDataCopy
,
valid
:
true
,
}
return
instructionSet
}
...
...
@@ -86,6 +102,7 @@ func NewHomesteadInstructionSet() [256]operation {
validateStack
:
makeStackFunc
(
6
,
1
),
memorySize
:
memoryDelegateCall
,
valid
:
true
,
returns
:
true
,
}
return
instructionSet
}
...
...
@@ -271,22 +288,22 @@ func NewFrontierInstructionSet() [256]operation {
valid
:
true
,
},
CALLDATALOAD
:
{
execute
:
opCall
d
ataLoad
,
execute
:
opCall
D
ataLoad
,
gasCost
:
constGasFunc
(
GasFastestStep
),
validateStack
:
makeStackFunc
(
1
,
1
),
valid
:
true
,
},
CALLDATASIZE
:
{
execute
:
opCall
d
ataSize
,
execute
:
opCall
D
ataSize
,
gasCost
:
constGasFunc
(
GasQuickStep
),
validateStack
:
makeStackFunc
(
0
,
1
),
valid
:
true
,
},
CALLDATACOPY
:
{
execute
:
opCall
d
ataCopy
,
gasCost
:
gasCall
d
ataCopy
,
execute
:
opCall
D
ataCopy
,
gasCost
:
gasCall
D
ataCopy
,
validateStack
:
makeStackFunc
(
3
,
0
),
memorySize
:
memoryCall
d
ataCopy
,
memorySize
:
memoryCall
D
ataCopy
,
valid
:
true
,
},
CODESIZE
:
{
...
...
@@ -867,6 +884,7 @@ func NewFrontierInstructionSet() [256]operation {
memorySize
:
memoryCreate
,
valid
:
true
,
writes
:
true
,
returns
:
true
,
},
CALL
:
{
execute
:
opCall
,
...
...
@@ -874,6 +892,7 @@ func NewFrontierInstructionSet() [256]operation {
validateStack
:
makeStackFunc
(
7
,
1
),
memorySize
:
memoryCall
,
valid
:
true
,
returns
:
true
,
},
CALLCODE
:
{
execute
:
opCallCode
,
...
...
@@ -881,6 +900,7 @@ func NewFrontierInstructionSet() [256]operation {
validateStack
:
makeStackFunc
(
7
,
1
),
memorySize
:
memoryCall
,
valid
:
true
,
returns
:
true
,
},
RETURN
:
{
execute
:
opReturn
,
...
...
core/vm/memory.go
View file @
0b978f91
...
...
@@ -22,7 +22,6 @@ import "fmt"
type
Memory
struct
{
store
[]
byte
lastGasCost
uint64
lastReturn
[]
byte
}
func
NewMemory
()
*
Memory
{
...
...
core/vm/memory_table.go
View file @
0b978f91
...
...
@@ -26,7 +26,11 @@ func memorySha3(stack *Stack) *big.Int {
return
calcMemSize
(
stack
.
Back
(
0
),
stack
.
Back
(
1
))
}
func
memoryCalldataCopy
(
stack
*
Stack
)
*
big
.
Int
{
func
memoryCallDataCopy
(
stack
*
Stack
)
*
big
.
Int
{
return
calcMemSize
(
stack
.
Back
(
0
),
stack
.
Back
(
2
))
}
func
memoryReturnDataCopy
(
stack
*
Stack
)
*
big
.
Int
{
return
calcMemSize
(
stack
.
Back
(
0
),
stack
.
Back
(
2
))
}
...
...
core/vm/opcodes.go
View file @
0b978f91
...
...
@@ -82,10 +82,11 @@ const (
GASPRICE
EXTCODESIZE
EXTCODECOPY
RETURNDATASIZE
RETURNDATACOPY
)
const
(
// 0x40 range - block operations
BLOCKHASH
OpCode
=
0x40
+
iota
COINBASE
...
...
@@ -250,6 +251,10 @@ var opCodeToString = map[OpCode]string{
CODESIZE
:
"CODESIZE"
,
CODECOPY
:
"CODECOPY"
,
GASPRICE
:
"GASPRICE"
,
EXTCODESIZE
:
"EXTCODESIZE"
,
EXTCODECOPY
:
"EXTCODECOPY"
,
RETURNDATASIZE
:
"RETURNDATASIZE"
,
RETURNDATACOPY
:
"RETURNDATACOPY"
,
// 0x40 range - block operations
BLOCKHASH
:
"BLOCKHASH"
,
...
...
@@ -258,8 +263,6 @@ var opCodeToString = map[OpCode]string{
NUMBER
:
"NUMBER"
,
DIFFICULTY
:
"DIFFICULTY"
,
GASLIMIT
:
"GASLIMIT"
,
EXTCODESIZE
:
"EXTCODESIZE"
,
EXTCODECOPY
:
"EXTCODECOPY"
,
// 0x50 range - 'storage' and execution
POP
:
"POP"
,
...
...
@@ -411,14 +414,16 @@ var stringToOp = map[string]OpCode{
"CODESIZE"
:
CODESIZE
,
"CODECOPY"
:
CODECOPY
,
"GASPRICE"
:
GASPRICE
,
"EXTCODESIZE"
:
EXTCODESIZE
,
"EXTCODECOPY"
:
EXTCODECOPY
,
"RETURNDATASIZE"
:
RETURNDATASIZE
,
"RETURNDATACOPY"
:
RETURNDATACOPY
,
"BLOCKHASH"
:
BLOCKHASH
,
"COINBASE"
:
COINBASE
,
"TIMESTAMP"
:
TIMESTAMP
,
"NUMBER"
:
NUMBER
,
"DIFFICULTY"
:
DIFFICULTY
,
"GASLIMIT"
:
GASLIMIT
,
"EXTCODESIZE"
:
EXTCODESIZE
,
"EXTCODECOPY"
:
EXTCODECOPY
,
"POP"
:
POP
,
"MLOAD"
:
MLOAD
,
"MSTORE"
:
MSTORE
,
...
...
testdata
@
85f6d7cc
Subproject commit 8
15151e4cea4e73328f8586b4e61c3d7e1e9e543
Subproject commit 8
5f6d7cc01b6bd04e071f5ba579fc675cfd2043b
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment