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
d078e9b8
Commit
d078e9b8
authored
Jun 13, 2014
by
obscuren
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactoring state transitioning
parent
b855e5f7
Changes
10
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
509 additions
and
191 deletions
+509
-191
asm.go
ethchain/asm.go
+3
-9
deprecated.go
ethchain/deprecated.go
+225
-0
error.go
ethchain/error.go
+17
-0
stack.go
ethchain/stack.go
+6
-0
state_manager.go
ethchain/state_manager.go
+178
-157
state_object.go
ethchain/state_object.go
+1
-1
transaction.go
ethchain/transaction.go
+10
-6
transaction_pool.go
ethchain/transaction_pool.go
+1
-1
types.go
ethchain/types.go
+6
-2
vm.go
ethchain/vm.go
+62
-15
No files found.
ethchain/asm.go
View file @
d078e9b8
...
...
@@ -25,16 +25,10 @@ func Disassemble(script []byte) (asm []string) {
pc
.
Add
(
pc
,
ethutil
.
Big1
)
a
:=
int64
(
op
)
-
int64
(
PUSH1
)
+
1
data
:=
script
[
pc
.
Int64
()
:
pc
.
Int64
()
+
a
]
val
:=
ethutil
.
BigD
(
data
)
var
b
[]
byte
if
val
.
Int64
()
==
0
{
b
=
[]
byte
{
0
}
}
else
{
b
=
val
.
Bytes
()
if
len
(
data
)
==
0
{
data
=
[]
byte
{
0
}
}
asm
=
append
(
asm
,
fmt
.
Sprintf
(
"0x%x"
,
b
))
asm
=
append
(
asm
,
fmt
.
Sprintf
(
"0x%x"
,
data
))
pc
.
Add
(
pc
,
big
.
NewInt
(
a
-
1
))
}
...
...
ethchain/deprecated.go
0 → 100644
View file @
d078e9b8
package
ethchain
import
(
"bytes"
"fmt"
"github.com/ethereum/eth-go/ethutil"
"math/big"
)
func
(
sm
*
StateManager
)
EvalScript
(
state
*
State
,
script
[]
byte
,
object
*
StateObject
,
tx
*
Transaction
,
block
*
Block
)
(
ret
[]
byte
,
gas
*
big
.
Int
,
err
error
)
{
account
:=
state
.
GetAccount
(
tx
.
Sender
())
err
=
account
.
ConvertGas
(
tx
.
Gas
,
tx
.
GasPrice
)
if
err
!=
nil
{
ethutil
.
Config
.
Log
.
Debugln
(
err
)
return
}
closure
:=
NewClosure
(
account
,
object
,
script
,
state
,
tx
.
Gas
,
tx
.
GasPrice
)
vm
:=
NewVm
(
state
,
sm
,
RuntimeVars
{
Origin
:
account
.
Address
(),
BlockNumber
:
block
.
BlockInfo
()
.
Number
,
PrevHash
:
block
.
PrevHash
,
Coinbase
:
block
.
Coinbase
,
Time
:
block
.
Time
,
Diff
:
block
.
Difficulty
,
Value
:
tx
.
Value
,
//Price: tx.GasPrice,
})
ret
,
gas
,
err
=
closure
.
Call
(
vm
,
tx
.
Data
,
nil
)
// Update the account (refunds)
state
.
UpdateStateObject
(
account
)
state
.
UpdateStateObject
(
object
)
return
}
func
(
self
*
StateManager
)
ProcessTransaction
(
tx
*
Transaction
,
coinbase
*
StateObject
,
state
*
State
,
toContract
bool
)
(
gas
*
big
.
Int
,
err
error
)
{
fmt
.
Printf
(
"state root before update %x
\n
"
,
state
.
Root
())
defer
func
()
{
if
r
:=
recover
();
r
!=
nil
{
ethutil
.
Config
.
Log
.
Infoln
(
r
)
err
=
fmt
.
Errorf
(
"%v"
,
r
)
}
}()
gas
=
new
(
big
.
Int
)
addGas
:=
func
(
g
*
big
.
Int
)
{
gas
.
Add
(
gas
,
g
)
}
addGas
(
GasTx
)
// Get the sender
sender
:=
state
.
GetAccount
(
tx
.
Sender
())
if
sender
.
Nonce
!=
tx
.
Nonce
{
err
=
NonceError
(
tx
.
Nonce
,
sender
.
Nonce
)
return
}
sender
.
Nonce
+=
1
defer
func
()
{
//state.UpdateStateObject(sender)
// Notify all subscribers
self
.
Ethereum
.
Reactor
()
.
Post
(
"newTx:post"
,
tx
)
}()
txTotalBytes
:=
big
.
NewInt
(
int64
(
len
(
tx
.
Data
)))
//fmt.Println("txTotalBytes", txTotalBytes)
//txTotalBytes.Div(txTotalBytes, ethutil.Big32)
addGas
(
new
(
big
.
Int
)
.
Mul
(
txTotalBytes
,
GasData
))
rGas
:=
new
(
big
.
Int
)
.
Set
(
gas
)
rGas
.
Mul
(
gas
,
tx
.
GasPrice
)
// Make sure there's enough in the sender's account. Having insufficient
// funds won't invalidate this transaction but simple ignores it.
totAmount
:=
new
(
big
.
Int
)
.
Add
(
tx
.
Value
,
rGas
)
if
sender
.
Amount
.
Cmp
(
totAmount
)
<
0
{
state
.
UpdateStateObject
(
sender
)
err
=
fmt
.
Errorf
(
"[TXPL] Insufficient amount in sender's (%x) account"
,
tx
.
Sender
())
return
}
coinbase
.
BuyGas
(
gas
,
tx
.
GasPrice
)
state
.
UpdateStateObject
(
coinbase
)
fmt
.
Printf
(
"1. root %x
\n
"
,
state
.
Root
())
// Get the receiver
receiver
:=
state
.
GetAccount
(
tx
.
Recipient
)
// Send Tx to self
if
bytes
.
Compare
(
tx
.
Recipient
,
tx
.
Sender
())
==
0
{
// Subtract the fee
sender
.
SubAmount
(
rGas
)
}
else
{
// Subtract the amount from the senders account
sender
.
SubAmount
(
totAmount
)
state
.
UpdateStateObject
(
sender
)
fmt
.
Printf
(
"3. root %x
\n
"
,
state
.
Root
())
// Add the amount to receivers account which should conclude this transaction
receiver
.
AddAmount
(
tx
.
Value
)
state
.
UpdateStateObject
(
receiver
)
fmt
.
Printf
(
"2. root %x
\n
"
,
state
.
Root
())
}
ethutil
.
Config
.
Log
.
Infof
(
"[TXPL] Processed Tx %x
\n
"
,
tx
.
Hash
())
return
}
func
(
sm
*
StateManager
)
ApplyTransaction
(
coinbase
[]
byte
,
state
*
State
,
block
*
Block
,
tx
*
Transaction
)
(
totalGasUsed
*
big
.
Int
,
err
error
)
{
/*
Applies transactions to the given state and creates new
state objects where needed.
If said objects needs to be created
run the initialization script provided by the transaction and
assume there's a return value. The return value will be set to
the script section of the state object.
*/
var
(
addTotalGas
=
func
(
gas
*
big
.
Int
)
{
totalGasUsed
.
Add
(
totalGasUsed
,
gas
)
}
gas
=
new
(
big
.
Int
)
script
[]
byte
)
totalGasUsed
=
big
.
NewInt
(
0
)
snapshot
:=
state
.
Snapshot
()
ca
:=
state
.
GetAccount
(
coinbase
)
// Apply the transaction to the current state
gas
,
err
=
sm
.
ProcessTransaction
(
tx
,
ca
,
state
,
false
)
addTotalGas
(
gas
)
fmt
.
Println
(
"gas used by tx"
,
gas
)
if
tx
.
CreatesContract
()
{
if
err
==
nil
{
// Create a new state object and the transaction
// as it's data provider.
contract
:=
sm
.
MakeStateObject
(
state
,
tx
)
if
contract
!=
nil
{
fmt
.
Println
(
Disassemble
(
contract
.
Init
()))
// Evaluate the initialization script
// and use the return value as the
// script section for the state object.
script
,
gas
,
err
=
sm
.
EvalScript
(
state
,
contract
.
Init
(),
contract
,
tx
,
block
)
fmt
.
Println
(
"gas used by eval"
,
gas
)
addTotalGas
(
gas
)
fmt
.
Println
(
"total ="
,
totalGasUsed
)
fmt
.
Println
(
"script len ="
,
len
(
script
))
if
err
!=
nil
{
err
=
fmt
.
Errorf
(
"[STATE] Error during init script run %v"
,
err
)
return
}
contract
.
script
=
script
state
.
UpdateStateObject
(
contract
)
}
else
{
err
=
fmt
.
Errorf
(
"[STATE] Unable to create contract"
)
}
}
else
{
err
=
fmt
.
Errorf
(
"[STATE] contract creation tx: %v for sender %x"
,
err
,
tx
.
Sender
())
}
}
else
{
// Find the state object at the "recipient" address. If
// there's an object attempt to run the script.
stateObject
:=
state
.
GetStateObject
(
tx
.
Recipient
)
if
err
==
nil
&&
stateObject
!=
nil
&&
len
(
stateObject
.
Script
())
>
0
{
_
,
gas
,
err
=
sm
.
EvalScript
(
state
,
stateObject
.
Script
(),
stateObject
,
tx
,
block
)
addTotalGas
(
gas
)
}
}
parent
:=
sm
.
bc
.
GetBlock
(
block
.
PrevHash
)
total
:=
new
(
big
.
Int
)
.
Add
(
block
.
GasUsed
,
totalGasUsed
)
limit
:=
block
.
CalcGasLimit
(
parent
)
if
total
.
Cmp
(
limit
)
>
0
{
state
.
Revert
(
snapshot
)
err
=
GasLimitError
(
total
,
limit
)
}
return
}
// Apply transactions uses the transaction passed to it and applies them onto
// the current processing state.
func
(
sm
*
StateManager
)
ApplyTransactions
(
coinbase
[]
byte
,
state
*
State
,
block
*
Block
,
txs
[]
*
Transaction
)
([]
*
Receipt
,
[]
*
Transaction
)
{
// Process each transaction/contract
var
receipts
[]
*
Receipt
var
validTxs
[]
*
Transaction
var
ignoredTxs
[]
*
Transaction
// Transactions which go over the gasLimit
totalUsedGas
:=
big
.
NewInt
(
0
)
for
_
,
tx
:=
range
txs
{
usedGas
,
err
:=
sm
.
ApplyTransaction
(
coinbase
,
state
,
block
,
tx
)
if
err
!=
nil
{
if
IsNonceErr
(
err
)
{
continue
}
if
IsGasLimitErr
(
err
)
{
ignoredTxs
=
append
(
ignoredTxs
,
tx
)
// We need to figure out if we want to do something with thse txes
ethutil
.
Config
.
Log
.
Debugln
(
"Gastlimit:"
,
err
)
continue
}
ethutil
.
Config
.
Log
.
Infoln
(
err
)
}
accumelative
:=
new
(
big
.
Int
)
.
Set
(
totalUsedGas
.
Add
(
totalUsedGas
,
usedGas
))
receipt
:=
&
Receipt
{
tx
,
ethutil
.
CopyBytes
(
state
.
Root
()
.
([]
byte
)),
accumelative
}
receipts
=
append
(
receipts
,
receipt
)
validTxs
=
append
(
validTxs
,
tx
)
}
fmt
.
Println
(
"################# MADE
\n
"
,
receipts
,
"
\n
############################"
)
// Update the total gas used for the block (to be mined)
block
.
GasUsed
=
totalUsedGas
return
receipts
,
validTxs
}
ethchain/error.go
View file @
d078e9b8
...
...
@@ -79,3 +79,20 @@ func IsNonceErr(err error) bool {
return
ok
}
type
OutOfGasErr
struct
{
Message
string
}
func
OutOfGasError
()
*
OutOfGasErr
{
return
&
OutOfGasErr
{
Message
:
"Out of gas"
}
}
func
(
self
*
OutOfGasErr
)
Error
()
string
{
return
self
.
Message
}
func
IsOutOfGasErr
(
err
error
)
bool
{
_
,
ok
:=
err
.
(
*
OutOfGasErr
)
return
ok
}
ethchain/stack.go
View file @
d078e9b8
...
...
@@ -111,6 +111,12 @@ func (m *Memory) Set(offset, size int64, value []byte) {
copy
(
m
.
store
[
offset
:
offset
+
size
],
value
)
}
func
(
m
*
Memory
)
Resize
(
size
uint64
)
{
if
uint64
(
m
.
Len
())
<
size
{
m
.
store
=
append
(
m
.
store
,
make
([]
byte
,
size
-
uint64
(
m
.
Len
()))
...
)
}
}
func
(
m
*
Memory
)
Get
(
offset
,
size
int64
)
[]
byte
{
return
m
.
store
[
offset
:
offset
+
size
]
}
...
...
ethchain/state_manager.go
View file @
d078e9b8
This diff is collapsed.
Click to expand it.
ethchain/state_object.go
View file @
d078e9b8
...
...
@@ -135,7 +135,7 @@ func (c *StateObject) ConvertGas(gas, price *big.Int) error {
func
(
self
*
StateObject
)
BuyGas
(
gas
,
price
*
big
.
Int
)
error
{
rGas
:=
new
(
big
.
Int
)
.
Set
(
gas
)
rGas
.
Mul
(
g
as
,
price
)
rGas
.
Mul
(
rG
as
,
price
)
self
.
AddAmount
(
rGas
)
...
...
ethchain/transaction.go
View file @
d078e9b8
...
...
@@ -46,15 +46,18 @@ func NewTransactionFromValue(val *ethutil.Value) *Transaction {
return
tx
}
func
(
self
*
Transaction
)
GasValue
()
*
big
.
Int
{
return
new
(
big
.
Int
)
.
Mul
(
self
.
Gas
,
self
.
GasPrice
)
}
func
(
self
*
Transaction
)
TotalValue
()
*
big
.
Int
{
v
:=
self
.
GasValue
()
return
v
.
Add
(
v
,
self
.
Value
)
}
func
(
tx
*
Transaction
)
Hash
()
[]
byte
{
data
:=
[]
interface
{}{
tx
.
Nonce
,
tx
.
GasPrice
,
tx
.
Gas
,
tx
.
Recipient
,
tx
.
Value
,
tx
.
Data
}
/*
if tx.contractCreation {
data = append(data, tx.Init)
}
*/
return
ethutil
.
Sha3Bin
(
ethutil
.
NewValue
(
data
)
.
Encode
())
}
...
...
@@ -185,6 +188,7 @@ type Receipt struct {
PostState
[]
byte
CumulativeGasUsed
*
big
.
Int
}
type
Receipts
[]
*
Receipt
func
NewRecieptFromValue
(
val
*
ethutil
.
Value
)
*
Receipt
{
r
:=
&
Receipt
{}
...
...
ethchain/transaction_pool.go
View file @
d078e9b8
...
...
@@ -220,7 +220,7 @@ out:
// Call blocking version.
pool
.
addTransaction
(
tx
)
ethutil
.
Config
.
Log
.
Debugf
(
"%x => %x (%v) %x
\n
"
,
tx
.
Sender
()[
:
4
],
tx
.
Recipient
[
:
4
],
tx
.
Value
,
tx
.
Hash
())
ethutil
.
Config
.
Log
.
Debugf
(
"
(t)
%x => %x (%v) %x
\n
"
,
tx
.
Sender
()[
:
4
],
tx
.
Recipient
[
:
4
],
tx
.
Value
,
tx
.
Hash
())
// Notify the subscribers
pool
.
Ethereum
.
Reactor
()
.
Post
(
"newTx:pre"
,
tx
)
...
...
ethchain/types.go
View file @
d078e9b8
...
...
@@ -21,8 +21,10 @@ const (
NEG
=
0x09
LT
=
0x0a
GT
=
0x0b
EQ
=
0x0c
NOT
=
0x0d
SLT
=
0x0c
SGT
=
0x0d
EQ
=
0x0e
NOT
=
0x0f
// 0x10 range - bit ops
AND
=
0x10
...
...
@@ -128,6 +130,8 @@ var opCodeToString = map[OpCode]string{
NEG
:
"NEG"
,
LT
:
"LT"
,
GT
:
"GT"
,
SLT
:
"SLT"
,
SGT
:
"SGT"
,
EQ
:
"EQ"
,
NOT
:
"NOT"
,
...
...
ethchain/vm.go
View file @
d078e9b8
...
...
@@ -5,6 +5,7 @@ import (
"fmt"
"github.com/ethereum/eth-go/ethutil"
_
"github.com/obscuren/secp256k1-go"
"math"
_
"math"
"math/big"
)
...
...
@@ -18,6 +19,7 @@ var (
GasCreate
=
big
.
NewInt
(
100
)
GasCall
=
big
.
NewInt
(
20
)
GasMemory
=
big
.
NewInt
(
1
)
GasData
=
big
.
NewInt
(
5
)
GasTx
=
big
.
NewInt
(
500
)
)
...
...
@@ -116,9 +118,8 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
gas
.
Add
(
gas
,
amount
)
}
var
newMemSize
uint64
=
0
switch
op
{
case
SHA3
:
setStepGasUsage
(
GasSha
)
case
SLOAD
:
setStepGasUsage
(
GasSLoad
)
case
SSTORE
:
...
...
@@ -135,27 +136,61 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
setStepGasUsage
(
new
(
big
.
Int
)
.
Mul
(
mult
,
GasSStore
))
case
BALANCE
:
setStepGasUsage
(
GasBalance
)
case
CREATE
:
case
MSTORE
:
require
(
2
)
newMemSize
=
stack
.
Peek
()
.
Uint64
()
+
32
case
MSTORE8
:
require
(
2
)
newMemSize
=
stack
.
Peek
()
.
Uint64
()
+
1
case
RETURN
:
require
(
2
)
newMemSize
=
stack
.
Peek
()
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
2
]
.
Uint64
()
case
SHA3
:
require
(
2
)
setStepGasUsage
(
GasSha
)
newMemSize
=
stack
.
Peek
()
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
2
]
.
Uint64
()
case
CALLDATACOPY
:
require
(
3
)
args
:=
stack
.
Get
(
big
.
NewInt
(
3
))
initSize
:=
new
(
big
.
Int
)
.
Add
(
args
[
1
],
args
[
0
])
newMemSize
=
stack
.
Peek
()
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
3
]
.
Uint64
()
case
CODECOPY
:
require
(
3
)
setStepGasUsage
(
CalculateTxGas
(
initSize
)
)
newMemSize
=
stack
.
Peek
()
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
3
]
.
Uint64
(
)
case
CALL
:
require
(
7
)
setStepGasUsage
(
GasCall
)
case
MLOAD
,
MSIZE
,
MSTORE8
,
MSTORE
:
setStepGasUsage
(
GasMemory
)
x
:=
stack
.
data
[
stack
.
Len
()
-
6
]
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
7
]
.
Uint64
()
y
:=
stack
.
data
[
stack
.
Len
()
-
4
]
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
5
]
.
Uint64
()
newMemSize
=
uint64
(
math
.
Max
(
float64
(
x
),
float64
(
y
)))
case
CREATE
:
require
(
3
)
setStepGasUsage
(
GasCreate
)
newMemSize
=
stack
.
data
[
stack
.
Len
()
-
2
]
.
Uint64
()
+
stack
.
data
[
stack
.
Len
()
-
3
]
.
Uint64
()
default
:
setStepGasUsage
(
GasStep
)
}
newMemSize
=
(
newMemSize
+
31
)
/
32
*
32
if
newMemSize
>
uint64
(
mem
.
Len
())
{
m
:=
GasMemory
.
Uint64
()
*
(
newMemSize
-
uint64
(
mem
.
Len
()))
/
32
setStepGasUsage
(
big
.
NewInt
(
int64
(
m
)))
}
if
!
closure
.
UseGas
(
gas
)
{
ethutil
.
Config
.
Log
.
Debugln
(
"Insufficient gas"
,
closure
.
Gas
,
gas
)
return
closure
.
Return
(
nil
),
fmt
.
Errorf
(
"insufficient gas %v %v"
,
closure
.
Gas
,
gas
)
}
mem
.
Resize
(
newMemSize
)
switch
op
{
case
LOG
:
stack
.
Print
()
...
...
@@ -340,6 +375,23 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
case
CALLDATACOPY
:
case
CODESIZE
:
case
CODECOPY
:
var
(
size
=
int64
(
len
(
closure
.
Script
))
mOff
=
stack
.
Pop
()
.
Int64
()
cOff
=
stack
.
Pop
()
.
Int64
()
l
=
stack
.
Pop
()
.
Int64
()
)
if
cOff
>
size
{
cOff
=
0
l
=
0
}
else
if
cOff
+
l
>
size
{
l
=
0
}
code
:=
closure
.
Script
[
cOff
:
cOff
+
l
]
mem
.
Set
(
mOff
,
l
,
code
)
case
GASPRICE
:
stack
.
Push
(
closure
.
Price
)
...
...
@@ -448,7 +500,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
// Transfer all remaining gas to the new
// contract so it may run the init script
gas
:=
new
(
big
.
Int
)
.
Set
(
closure
.
Gas
)
closure
.
UseGas
(
gas
)
//
closure.UseGas(gas)
// Create the closure
c
:=
NewClosure
(
closure
.
callee
,
...
...
@@ -498,12 +550,7 @@ func (vm *Vm) RunClosure(closure *Closure, hook DebugHook) (ret []byte, err erro
if
contract
!=
nil
{
// Prepay for the gas
// If gas is set to 0 use all remaining gas for the next call
if
gas
.
Cmp
(
big
.
NewInt
(
0
))
==
0
{
// Copy
gas
=
new
(
big
.
Int
)
.
Set
(
closure
.
Gas
)
}
closure
.
UseGas
(
gas
)
//closure.UseGas(gas)
// Add the value to the state object
contract
.
AddAmount
(
value
)
...
...
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