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
8a22cd5e
Commit
8a22cd5e
authored
Mar 27, 2015
by
obscuren
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Removed defer/panic. #503
parent
00f8319f
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
180 additions
and
120 deletions
+180
-120
gas.go
core/vm/gas.go
+94
-70
memory.go
core/vm/memory.go
+21
-17
stack.go
core/vm/stack.go
+4
-6
vm.go
core/vm/vm.go
+61
-27
No files found.
core/vm/gas.go
View file @
8a22cd5e
package
vm
import
"math/big"
type
req
struct
{
stack
int
gas
*
big
.
Int
}
import
(
"fmt"
"math/big"
)
var
(
GasQuickStep
=
big
.
NewInt
(
2
)
...
...
@@ -56,75 +54,30 @@ var (
GasCopyWord
=
big
.
NewInt
(
3
)
)
var
_baseCheck
=
map
[
OpCode
]
req
{
// Req stack Gas price
ADD
:
{
2
,
GasFastestStep
},
LT
:
{
2
,
GasFastestStep
},
GT
:
{
2
,
GasFastestStep
},
SLT
:
{
2
,
GasFastestStep
},
SGT
:
{
2
,
GasFastestStep
},
EQ
:
{
2
,
GasFastestStep
},
ISZERO
:
{
1
,
GasFastestStep
},
SUB
:
{
2
,
GasFastestStep
},
AND
:
{
2
,
GasFastestStep
},
OR
:
{
2
,
GasFastestStep
},
XOR
:
{
2
,
GasFastestStep
},
NOT
:
{
1
,
GasFastestStep
},
BYTE
:
{
2
,
GasFastestStep
},
CALLDATALOAD
:
{
1
,
GasFastestStep
},
CALLDATACOPY
:
{
3
,
GasFastestStep
},
MLOAD
:
{
1
,
GasFastestStep
},
MSTORE
:
{
2
,
GasFastestStep
},
MSTORE8
:
{
2
,
GasFastestStep
},
CODECOPY
:
{
3
,
GasFastestStep
},
MUL
:
{
2
,
GasFastStep
},
DIV
:
{
2
,
GasFastStep
},
SDIV
:
{
2
,
GasFastStep
},
MOD
:
{
2
,
GasFastStep
},
SMOD
:
{
2
,
GasFastStep
},
SIGNEXTEND
:
{
2
,
GasFastStep
},
ADDMOD
:
{
3
,
GasMidStep
},
MULMOD
:
{
3
,
GasMidStep
},
JUMP
:
{
1
,
GasMidStep
},
JUMPI
:
{
2
,
GasSlowStep
},
EXP
:
{
2
,
GasSlowStep
},
ADDRESS
:
{
0
,
GasQuickStep
},
ORIGIN
:
{
0
,
GasQuickStep
},
CALLER
:
{
0
,
GasQuickStep
},
CALLVALUE
:
{
0
,
GasQuickStep
},
CODESIZE
:
{
0
,
GasQuickStep
},
GASPRICE
:
{
0
,
GasQuickStep
},
COINBASE
:
{
0
,
GasQuickStep
},
TIMESTAMP
:
{
0
,
GasQuickStep
},
NUMBER
:
{
0
,
GasQuickStep
},
CALLDATASIZE
:
{
0
,
GasQuickStep
},
DIFFICULTY
:
{
0
,
GasQuickStep
},
GASLIMIT
:
{
0
,
GasQuickStep
},
POP
:
{
0
,
GasQuickStep
},
PC
:
{
0
,
GasQuickStep
},
MSIZE
:
{
0
,
GasQuickStep
},
GAS
:
{
0
,
GasQuickStep
},
BLOCKHASH
:
{
1
,
GasExtStep
},
BALANCE
:
{
0
,
GasExtStep
},
EXTCODESIZE
:
{
1
,
GasExtStep
},
EXTCODECOPY
:
{
4
,
GasExtStep
},
SLOAD
:
{
1
,
GasStorageGet
},
SSTORE
:
{
2
,
Zero
},
SHA3
:
{
1
,
GasSha3Base
},
CREATE
:
{
3
,
GasCreate
},
CALL
:
{
7
,
GasCall
},
CALLCODE
:
{
7
,
GasCall
},
JUMPDEST
:
{
0
,
GasJumpDest
},
SUICIDE
:
{
1
,
Zero
},
RETURN
:
{
2
,
Zero
},
}
func
baseCheck
(
op
OpCode
,
stack
*
stack
,
gas
*
big
.
Int
)
error
{
// PUSH and DUP are a bit special. They all cost the same but we do want to have checking on stack push limit
// PUSH is also allowed to calculate the same price for all PUSHes
// DUP requirements are handled elsewhere (except for the stack limit check)
if
op
>=
PUSH1
&&
op
<=
PUSH32
{
op
=
PUSH1
}
if
op
>=
SWAP1
&&
op
<=
SWAP16
{
op
=
SWAP1
}
func
baseCheck
(
op
OpCode
,
stack
*
stack
,
gas
*
big
.
Int
)
{
if
r
,
ok
:=
_baseCheck
[
op
];
ok
{
stack
.
require
(
r
.
stack
)
err
:=
stack
.
require
(
r
.
stackPop
)
if
err
!=
nil
{
return
err
}
if
r
.
stackPush
&&
len
(
stack
.
data
)
-
r
.
stackPop
==
1024
{
return
fmt
.
Errorf
(
"stack limit reached (%d)"
,
maxStack
)
}
gas
.
Add
(
gas
,
r
.
gas
)
}
return
nil
}
func
toWordSize
(
size
*
big
.
Int
)
*
big
.
Int
{
...
...
@@ -133,3 +86,74 @@ func toWordSize(size *big.Int) *big.Int {
tmp
.
Div
(
tmp
,
u256
(
32
))
return
tmp
}
type
req
struct
{
stackPop
int
gas
*
big
.
Int
stackPush
bool
}
var
_baseCheck
=
map
[
OpCode
]
req
{
// opcode | stack pop | gas price | stack push
ADD
:
{
2
,
GasFastestStep
,
true
},
LT
:
{
2
,
GasFastestStep
,
true
},
GT
:
{
2
,
GasFastestStep
,
true
},
SLT
:
{
2
,
GasFastestStep
,
true
},
SGT
:
{
2
,
GasFastestStep
,
true
},
EQ
:
{
2
,
GasFastestStep
,
true
},
ISZERO
:
{
1
,
GasFastestStep
,
true
},
SUB
:
{
2
,
GasFastestStep
,
true
},
AND
:
{
2
,
GasFastestStep
,
true
},
OR
:
{
2
,
GasFastestStep
,
true
},
XOR
:
{
2
,
GasFastestStep
,
true
},
NOT
:
{
1
,
GasFastestStep
,
true
},
BYTE
:
{
2
,
GasFastestStep
,
true
},
CALLDATALOAD
:
{
1
,
GasFastestStep
,
true
},
CALLDATACOPY
:
{
3
,
GasFastestStep
,
true
},
MLOAD
:
{
1
,
GasFastestStep
,
true
},
MSTORE
:
{
2
,
GasFastestStep
,
false
},
MSTORE8
:
{
2
,
GasFastestStep
,
false
},
CODECOPY
:
{
3
,
GasFastestStep
,
false
},
MUL
:
{
2
,
GasFastStep
,
true
},
DIV
:
{
2
,
GasFastStep
,
true
},
SDIV
:
{
2
,
GasFastStep
,
true
},
MOD
:
{
2
,
GasFastStep
,
true
},
SMOD
:
{
2
,
GasFastStep
,
true
},
SIGNEXTEND
:
{
2
,
GasFastStep
,
true
},
ADDMOD
:
{
3
,
GasMidStep
,
true
},
MULMOD
:
{
3
,
GasMidStep
,
true
},
JUMP
:
{
1
,
GasMidStep
,
false
},
JUMPI
:
{
2
,
GasSlowStep
,
false
},
EXP
:
{
2
,
GasSlowStep
,
true
},
ADDRESS
:
{
0
,
GasQuickStep
,
true
},
ORIGIN
:
{
0
,
GasQuickStep
,
true
},
CALLER
:
{
0
,
GasQuickStep
,
true
},
CALLVALUE
:
{
0
,
GasQuickStep
,
true
},
CODESIZE
:
{
0
,
GasQuickStep
,
true
},
GASPRICE
:
{
0
,
GasQuickStep
,
true
},
COINBASE
:
{
0
,
GasQuickStep
,
true
},
TIMESTAMP
:
{
0
,
GasQuickStep
,
true
},
NUMBER
:
{
0
,
GasQuickStep
,
true
},
CALLDATASIZE
:
{
0
,
GasQuickStep
,
true
},
DIFFICULTY
:
{
0
,
GasQuickStep
,
true
},
GASLIMIT
:
{
0
,
GasQuickStep
,
true
},
POP
:
{
1
,
GasQuickStep
,
false
},
PC
:
{
0
,
GasQuickStep
,
true
},
MSIZE
:
{
0
,
GasQuickStep
,
true
},
GAS
:
{
0
,
GasQuickStep
,
true
},
BLOCKHASH
:
{
1
,
GasExtStep
,
true
},
BALANCE
:
{
0
,
GasExtStep
,
true
},
EXTCODESIZE
:
{
1
,
GasExtStep
,
true
},
EXTCODECOPY
:
{
4
,
GasExtStep
,
false
},
SLOAD
:
{
1
,
GasStorageGet
,
true
},
SSTORE
:
{
2
,
Zero
,
false
},
SHA3
:
{
1
,
GasSha3Base
,
true
},
CREATE
:
{
3
,
GasCreate
,
true
},
CALL
:
{
7
,
GasCall
,
true
},
CALLCODE
:
{
7
,
GasCall
,
true
},
JUMPDEST
:
{
0
,
GasJumpDest
,
false
},
SUICIDE
:
{
1
,
Zero
,
false
},
RETURN
:
{
2
,
Zero
,
false
},
PUSH1
:
{
0
,
GasFastStep
,
true
},
DUP1
:
{
0
,
Zero
,
true
},
}
core/vm/memory.go
View file @
8a22cd5e
...
...
@@ -15,28 +15,32 @@ func NewMemory() *Memory {
}
func
(
m
*
Memory
)
Set
(
offset
,
size
uint64
,
value
[]
byte
)
{
// If the length of the store is 0 this is a complete failure
// memory size is set prior to calling this method so enough size
// should always be available.
if
len
(
m
.
store
)
==
0
{
// length of store may never be less than offset + size.
// The store should be resized PRIOR to setting the memory
if
size
>
uint64
(
len
(
m
.
store
))
{
panic
(
"INVALID memory: store empty"
)
}
value
=
common
.
RightPadBytes
(
value
,
int
(
size
))
// It's possible the offset is greater than 0 and size equals 0. This is because
// the calcMemSize (common.go) could potentially return 0 when size is zero (NO-OP)
if
size
>
0
{
copy
(
m
.
store
[
offset
:
offset
+
size
],
common
.
RightPadBytes
(
value
,
int
(
size
)))
}
totSize
:=
offset
+
size
lenSize
:=
int64
(
len
(
m
.
store
)
-
1
)
if
totSize
>
lenSize
{
// Calculate the diff between the sizes
diff
:=
totSize
-
lenSize
if
diff
>
0
{
// Create a new empty slice and append it
newSlice
:=
make
([]
byte
,
diff
-
1
)
// Resize slice
m
.
store
=
append
(
m
.
store
,
newSlice
...
)
/*
totSize := offset + size
lenSize := uint64(len(m.store) - 1)
if totSize > lenSize {
// Calculate the diff between the sizes
diff := totSize - lenSize
if diff > 0 {
// Create a new empty slice and append it
newSlice := make([]byte, diff-1)
// Resize slice
m.store = append(m.store, newSlice...)
}
}
}
copy
(
m
.
store
[
offset
:
offset
+
size
],
value
)
*/
}
func
(
m
*
Memory
)
Resize
(
size
uint64
)
{
...
...
core/vm/stack.go
View file @
8a22cd5e
...
...
@@ -17,10 +17,7 @@ type stack struct {
}
func
(
st
*
stack
)
push
(
d
*
big
.
Int
)
{
if
len
(
st
.
data
)
==
maxStack
{
panic
(
fmt
.
Sprintf
(
"stack limit reached (%d)"
,
maxStack
))
}
// NOTE push limit (1024) is checked in baseCheck
stackItem
:=
new
(
big
.
Int
)
.
Set
(
d
)
if
len
(
st
.
data
)
>
st
.
ptr
{
st
.
data
[
st
.
ptr
]
=
stackItem
...
...
@@ -52,10 +49,11 @@ func (st *stack) peek() *big.Int {
return
st
.
data
[
st
.
len
()
-
1
]
}
func
(
st
*
stack
)
require
(
n
int
)
{
func
(
st
*
stack
)
require
(
n
int
)
error
{
if
st
.
len
()
<
n
{
panic
(
fmt
.
Sprintf
(
"stack underflow (%d <=> %d)"
,
len
(
st
.
data
),
n
)
)
return
fmt
.
Errorf
(
"stack underflow (%d <=> %d)"
,
len
(
st
.
data
),
n
)
}
return
nil
}
func
(
st
*
stack
)
Print
()
{
...
...
core/vm/vm.go
View file @
8a22cd5e
...
...
@@ -45,20 +45,32 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
self
.
Printf
(
"(%d) (%x) %x (code=%d) gas: %v (d) %x"
,
self
.
env
.
Depth
(),
caller
.
Address
()
.
Bytes
()[
:
4
],
context
.
Address
(),
len
(
code
),
context
.
Gas
,
callData
)
.
Endl
()
if
self
.
Recoverable
{
// Recover from any require exception
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
self
.
Printf
(
" %v"
,
r
)
.
Endl
()
/*
if self.Recoverable {
// Recover from any require exception
defer func() {
if r := recover(); r != nil {
self.Printf(" %v", r).Endl()
context
.
UseGas
(
context
.
Gas
)
context.UseGas(context.Gas)
ret
=
context
.
Return
(
nil
)
ret = context.Return(nil)
err
=
fmt
.
Errorf
(
"%v"
,
r
)
}
}()
}
err = fmt.Errorf("%v", r)
}
}()
}
*/
defer
func
()
{
if
err
!=
nil
{
self
.
Printf
(
" %v"
,
err
)
.
Endl
()
// In case of a VM exception (known exceptions) all gas consumed (panics NOT included).
context
.
UseGas
(
context
.
Gas
)
ret
=
context
.
Return
(
nil
)
}
}()
if
context
.
CodeAddr
!=
nil
{
if
p
:=
Precompiled
[
context
.
CodeAddr
.
Str
()];
p
!=
nil
{
...
...
@@ -76,18 +88,20 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
step
=
0
statedb
=
self
.
env
.
State
()
jump
=
func
(
from
uint64
,
to
*
big
.
Int
)
{
jump
=
func
(
from
uint64
,
to
*
big
.
Int
)
error
{
p
:=
to
.
Uint64
()
nop
:=
context
.
GetOp
(
p
)
if
!
destinations
.
Has
(
p
)
{
panic
(
fmt
.
Sprintf
(
"invalid jump destination (%v) %v"
,
nop
,
p
)
)
return
fmt
.
Errorf
(
"invalid jump destination (%v) %v"
,
nop
,
p
)
}
self
.
Printf
(
" ~> %v"
,
to
)
pc
=
to
.
Uint64
()
self
.
Endl
()
return
nil
}
)
...
...
@@ -105,7 +119,10 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
op
=
context
.
GetOp
(
pc
)
self
.
Printf
(
"(pc) %-3d -o- %-14s (m) %-4d (s) %-4d "
,
pc
,
op
.
String
(),
mem
.
Len
(),
stack
.
len
())
newMemSize
,
gas
:=
self
.
calculateGasAndSize
(
context
,
caller
,
op
,
statedb
,
mem
,
stack
)
newMemSize
,
gas
,
err
:=
self
.
calculateGasAndSize
(
context
,
caller
,
op
,
statedb
,
mem
,
stack
)
if
err
!=
nil
{
return
nil
,
err
}
self
.
Printf
(
"(g) %-3v (%v)"
,
gas
,
context
.
Gas
)
...
...
@@ -600,14 +617,18 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
self
.
Printf
(
" {0x%x : 0x%x}"
,
loc
,
val
.
Bytes
())
case
JUMP
:
jump
(
pc
,
stack
.
pop
())
if
err
:=
jump
(
pc
,
stack
.
pop
());
err
!=
nil
{
return
nil
,
err
}
continue
case
JUMPI
:
pos
,
cond
:=
stack
.
pop
(),
stack
.
pop
()
if
cond
.
Cmp
(
common
.
BigTrue
)
>=
0
{
jump
(
pc
,
pos
)
if
err
:=
jump
(
pc
,
pos
);
err
!=
nil
{
return
nil
,
err
}
continue
}
...
...
@@ -720,7 +741,7 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
default
:
self
.
Printf
(
"(pc) %-3v Invalid opcode %x
\n
"
,
pc
,
op
)
.
Endl
()
panic
(
fmt
.
Errorf
(
"Invalid opcode %x"
,
op
)
)
return
nil
,
fmt
.
Errorf
(
"Invalid opcode %x"
,
op
)
}
pc
++
...
...
@@ -729,28 +750,38 @@ func (self *Vm) Run(context *Context, callData []byte) (ret []byte, err error) {
}
}
func
(
self
*
Vm
)
calculateGasAndSize
(
context
*
Context
,
caller
ContextRef
,
op
OpCode
,
statedb
*
state
.
StateDB
,
mem
*
Memory
,
stack
*
stack
)
(
*
big
.
Int
,
*
big
.
Int
)
{
func
(
self
*
Vm
)
calculateGasAndSize
(
context
*
Context
,
caller
ContextRef
,
op
OpCode
,
statedb
*
state
.
StateDB
,
mem
*
Memory
,
stack
*
stack
)
(
*
big
.
Int
,
*
big
.
Int
,
error
)
{
var
(
gas
=
new
(
big
.
Int
)
newMemSize
*
big
.
Int
=
new
(
big
.
Int
)
)
baseCheck
(
op
,
stack
,
gas
)
err
:=
baseCheck
(
op
,
stack
,
gas
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
// stack Check, memory resize & gas phase
switch
op
{
case
PUSH1
,
PUSH2
,
PUSH3
,
PUSH4
,
PUSH5
,
PUSH6
,
PUSH7
,
PUSH8
,
PUSH9
,
PUSH10
,
PUSH11
,
PUSH12
,
PUSH13
,
PUSH14
,
PUSH15
,
PUSH16
,
PUSH17
,
PUSH18
,
PUSH19
,
PUSH20
,
PUSH21
,
PUSH22
,
PUSH23
,
PUSH24
,
PUSH25
,
PUSH26
,
PUSH27
,
PUSH28
,
PUSH29
,
PUSH30
,
PUSH31
,
PUSH32
:
gas
.
Set
(
GasFastestStep
)
case
SWAP1
,
SWAP2
,
SWAP3
,
SWAP4
,
SWAP5
,
SWAP6
,
SWAP7
,
SWAP8
,
SWAP9
,
SWAP10
,
SWAP11
,
SWAP12
,
SWAP13
,
SWAP14
,
SWAP15
,
SWAP16
:
n
:=
int
(
op
-
SWAP1
+
2
)
stack
.
require
(
n
)
err
:=
stack
.
require
(
n
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
gas
.
Set
(
GasFastestStep
)
case
DUP1
,
DUP2
,
DUP3
,
DUP4
,
DUP5
,
DUP6
,
DUP7
,
DUP8
,
DUP9
,
DUP10
,
DUP11
,
DUP12
,
DUP13
,
DUP14
,
DUP15
,
DUP16
:
n
:=
int
(
op
-
DUP1
+
1
)
stack
.
require
(
n
)
err
:=
stack
.
require
(
n
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
gas
.
Set
(
GasFastestStep
)
case
LOG0
,
LOG1
,
LOG2
,
LOG3
,
LOG4
:
n
:=
int
(
op
-
LOG0
)
stack
.
require
(
n
+
2
)
err
:=
stack
.
require
(
n
+
2
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
mSize
,
mStart
:=
stack
.
data
[
stack
.
len
()
-
2
],
stack
.
data
[
stack
.
len
()
-
1
]
...
...
@@ -762,7 +793,10 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
case
EXP
:
gas
.
Add
(
gas
,
new
(
big
.
Int
)
.
Mul
(
big
.
NewInt
(
int64
(
len
(
stack
.
data
[
stack
.
len
()
-
2
]
.
Bytes
()))),
GasExpByte
))
case
SSTORE
:
stack
.
require
(
2
)
err
:=
stack
.
require
(
2
)
if
err
!=
nil
{
return
nil
,
nil
,
err
}
var
g
*
big
.
Int
y
,
x
:=
stack
.
data
[
stack
.
len
()
-
2
],
stack
.
data
[
stack
.
len
()
-
1
]
...
...
@@ -853,7 +887,7 @@ func (self *Vm) calculateGasAndSize(context *Context, caller ContextRef, op OpCo
}
}
return
newMemSize
,
gas
return
newMemSize
,
gas
,
nil
}
func
(
self
*
Vm
)
RunPrecompiled
(
p
*
PrecompiledAccount
,
callData
[]
byte
,
context
*
Context
)
(
ret
[]
byte
,
err
error
)
{
...
...
@@ -869,7 +903,7 @@ func (self *Vm) RunPrecompiled(p *PrecompiledAccount, callData []byte, context *
tmp
:=
new
(
big
.
Int
)
.
Set
(
context
.
Gas
)
panic
(
OOG
(
gas
,
tmp
)
.
Error
()
)
return
nil
,
OOG
(
gas
,
tmp
)
}
}
...
...
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