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
2e14aff8
Commit
2e14aff8
authored
Sep 26, 2016
by
Péter Szilágyi
Committed by
GitHub
Sep 26, 2016
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #3037 from karalabe/state-caching
State caching
parents
e859f369
a59a93f4
Changes
17
Show whitespace changes
Inline
Side-by-side
Showing
17 changed files
with
414 additions
and
336 deletions
+414
-336
simulated.go
accounts/abi/bind/backends/simulated.go
+2
-5
blockchain.go
core/blockchain.go
+22
-13
chain_makers_test.go
core/chain_makers_test.go
+1
-1
dump.go
core/state/dump.go
+20
-27
managed_state.go
core/state/managed_state.go
+10
-11
managed_state_test.go
core/state/managed_state_test.go
+7
-6
state_object.go
core/state/state_object.go
+171
-131
state_test.go
core/state/state_test.go
+28
-22
statedb.go
core/state/statedb.go
+131
-98
environment.go
core/vm/environment.go
+1
-0
instructions.go
core/vm/instructions.go
+1
-1
api.go
eth/api.go
+3
-3
api.go
internal/ethapi/api.go
+2
-2
state_test.go
light/state_test.go
+1
-1
state_test_util.go
tests/state_test_util.go
+3
-3
util.go
tests/util.go
+8
-7
vm_test_util.go
tests/vm_test_util.go
+3
-5
No files found.
accounts/abi/bind/backends/simulated.go
View file @
2e14aff8
...
@@ -135,11 +135,8 @@ func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Addres
...
@@ -135,11 +135,8 @@ func (b *SimulatedBackend) StorageAt(ctx context.Context, contract common.Addres
return
nil
,
errBlockNumberUnsupported
return
nil
,
errBlockNumberUnsupported
}
}
statedb
,
_
:=
b
.
blockchain
.
State
()
statedb
,
_
:=
b
.
blockchain
.
State
()
if
obj
:=
statedb
.
GetStateObject
(
contract
);
obj
!=
nil
{
val
:=
statedb
.
GetState
(
contract
,
key
)
val
:=
obj
.
GetState
(
key
)
return
val
[
:
],
nil
return
val
[
:
],
nil
}
return
nil
,
nil
}
}
// TransactionReceipt returns the receipt of a transaction.
// TransactionReceipt returns the receipt of a transaction.
...
...
core/blockchain.go
View file @
2e14aff8
...
@@ -93,6 +93,7 @@ type BlockChain struct {
...
@@ -93,6 +93,7 @@ type BlockChain struct {
currentBlock
*
types
.
Block
// Current head of the block chain
currentBlock
*
types
.
Block
// Current head of the block chain
currentFastBlock
*
types
.
Block
// Current head of the fast-sync chain (may be above the block chain!)
currentFastBlock
*
types
.
Block
// Current head of the fast-sync chain (may be above the block chain!)
stateCache
*
state
.
StateDB
// State database to reuse between imports (contains state cache)
bodyCache
*
lru
.
Cache
// Cache for the most recent block bodies
bodyCache
*
lru
.
Cache
// Cache for the most recent block bodies
bodyRLPCache
*
lru
.
Cache
// Cache for the most recent block bodies in RLP encoded format
bodyRLPCache
*
lru
.
Cache
// Cache for the most recent block bodies in RLP encoded format
blockCache
*
lru
.
Cache
// Cache for the most recent entire blocks
blockCache
*
lru
.
Cache
// Cache for the most recent entire blocks
...
@@ -196,7 +197,15 @@ func (self *BlockChain) loadLastState() error {
...
@@ -196,7 +197,15 @@ func (self *BlockChain) loadLastState() error {
self
.
currentFastBlock
=
block
self
.
currentFastBlock
=
block
}
}
}
}
// Issue a status log and return
// Initialize a statedb cache to ensure singleton account bloom filter generation
statedb
,
err
:=
state
.
New
(
self
.
currentBlock
.
Root
(),
self
.
chainDb
)
if
err
!=
nil
{
return
err
}
self
.
stateCache
=
statedb
self
.
stateCache
.
GetAccount
(
common
.
Address
{})
// Issue a status log for the user
headerTd
:=
self
.
GetTd
(
currentHeader
.
Hash
(),
currentHeader
.
Number
.
Uint64
())
headerTd
:=
self
.
GetTd
(
currentHeader
.
Hash
(),
currentHeader
.
Number
.
Uint64
())
blockTd
:=
self
.
GetTd
(
self
.
currentBlock
.
Hash
(),
self
.
currentBlock
.
NumberU64
())
blockTd
:=
self
.
GetTd
(
self
.
currentBlock
.
Hash
(),
self
.
currentBlock
.
NumberU64
())
fastTd
:=
self
.
GetTd
(
self
.
currentFastBlock
.
Hash
(),
self
.
currentFastBlock
.
NumberU64
())
fastTd
:=
self
.
GetTd
(
self
.
currentFastBlock
.
Hash
(),
self
.
currentFastBlock
.
NumberU64
())
...
@@ -826,7 +835,6 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
...
@@ -826,7 +835,6 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
tstart
=
time
.
Now
()
tstart
=
time
.
Now
()
nonceChecked
=
make
([]
bool
,
len
(
chain
))
nonceChecked
=
make
([]
bool
,
len
(
chain
))
statedb
*
state
.
StateDB
)
)
// Start the parallel nonce verifier.
// Start the parallel nonce verifier.
...
@@ -893,29 +901,30 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
...
@@ -893,29 +901,30 @@ func (self *BlockChain) InsertChain(chain types.Blocks) (int, error) {
// Create a new statedb using the parent block and report an
// Create a new statedb using the parent block and report an
// error if it fails.
// error if it fails.
if
statedb
==
nil
{
switch
{
statedb
,
err
=
state
.
New
(
self
.
GetBlock
(
block
.
ParentHash
(),
block
.
NumberU64
()
-
1
)
.
Root
(),
self
.
chainDb
)
case
i
==
0
:
}
else
{
err
=
self
.
stateCache
.
Reset
(
self
.
GetBlock
(
block
.
ParentHash
(),
block
.
NumberU64
()
-
1
)
.
Root
())
err
=
statedb
.
Reset
(
chain
[
i
-
1
]
.
Root
())
default
:
err
=
self
.
stateCache
.
Reset
(
chain
[
i
-
1
]
.
Root
())
}
}
if
err
!=
nil
{
if
err
!=
nil
{
reportBlock
(
block
,
err
)
reportBlock
(
block
,
err
)
return
i
,
err
return
i
,
err
}
}
// Process block using the parent state as reference point.
// Process block using the parent state as reference point.
receipts
,
logs
,
usedGas
,
err
:=
self
.
processor
.
Process
(
block
,
s
tatedb
,
self
.
config
.
VmConfig
)
receipts
,
logs
,
usedGas
,
err
:=
self
.
processor
.
Process
(
block
,
s
elf
.
stateCache
,
self
.
config
.
VmConfig
)
if
err
!=
nil
{
if
err
!=
nil
{
reportBlock
(
block
,
err
)
reportBlock
(
block
,
err
)
return
i
,
err
return
i
,
err
}
}
// Validate the state using the default validator
// Validate the state using the default validator
err
=
self
.
Validator
()
.
ValidateState
(
block
,
self
.
GetBlock
(
block
.
ParentHash
(),
block
.
NumberU64
()
-
1
),
s
tatedb
,
receipts
,
usedGas
)
err
=
self
.
Validator
()
.
ValidateState
(
block
,
self
.
GetBlock
(
block
.
ParentHash
(),
block
.
NumberU64
()
-
1
),
s
elf
.
stateCache
,
receipts
,
usedGas
)
if
err
!=
nil
{
if
err
!=
nil
{
reportBlock
(
block
,
err
)
reportBlock
(
block
,
err
)
return
i
,
err
return
i
,
err
}
}
// Write state changes to database
// Write state changes to database
_
,
err
=
s
tatedb
.
Commit
()
_
,
err
=
s
elf
.
stateCache
.
Commit
()
if
err
!=
nil
{
if
err
!=
nil
{
return
i
,
err
return
i
,
err
}
}
...
...
core/chain_makers_test.go
View file @
2e14aff8
...
@@ -79,7 +79,7 @@ func ExampleGenerateChain() {
...
@@ -79,7 +79,7 @@ func ExampleGenerateChain() {
evmux
:=
&
event
.
TypeMux
{}
evmux
:=
&
event
.
TypeMux
{}
blockchain
,
_
:=
NewBlockChain
(
db
,
MakeChainConfig
(),
FakePow
{},
evmux
)
blockchain
,
_
:=
NewBlockChain
(
db
,
MakeChainConfig
(),
FakePow
{},
evmux
)
if
i
,
err
:=
blockchain
.
InsertChain
(
chain
);
err
!=
nil
{
if
i
,
err
:=
blockchain
.
InsertChain
(
chain
);
err
!=
nil
{
fmt
.
Printf
(
"insert error (block %d): %v
\n
"
,
i
,
err
)
fmt
.
Printf
(
"insert error (block %d): %v
\n
"
,
chain
[
i
]
.
NumberU64
()
,
err
)
return
return
}
}
...
...
core/state/dump.go
View file @
2e14aff8
...
@@ -21,9 +21,10 @@ import (
...
@@ -21,9 +21,10 @@ import (
"fmt"
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/rlp"
)
)
type
Account
struct
{
type
Dump
Account
struct
{
Balance
string
`json:"balance"`
Balance
string
`json:"balance"`
Nonce
uint64
`json:"nonce"`
Nonce
uint64
`json:"nonce"`
Root
string
`json:"root"`
Root
string
`json:"root"`
...
@@ -32,40 +33,41 @@ type Account struct {
...
@@ -32,40 +33,41 @@ type Account struct {
Storage
map
[
string
]
string
`json:"storage"`
Storage
map
[
string
]
string
`json:"storage"`
}
}
type
World
struct
{
type
Dump
struct
{
Root
string
`json:"root"`
Root
string
`json:"root"`
Accounts
map
[
string
]
Account
`json:"accounts"`
Accounts
map
[
string
]
Dump
Account
`json:"accounts"`
}
}
func
(
self
*
StateDB
)
RawDump
()
World
{
func
(
self
*
StateDB
)
RawDump
()
Dump
{
world
:=
World
{
dump
:=
Dump
{
Root
:
common
.
Bytes2Hex
(
self
.
trie
.
Root
()),
Root
:
common
.
Bytes2Hex
(
self
.
trie
.
Root
()),
Accounts
:
make
(
map
[
string
]
Account
),
Accounts
:
make
(
map
[
string
]
Dump
Account
),
}
}
it
:=
self
.
trie
.
Iterator
()
it
:=
self
.
trie
.
Iterator
()
for
it
.
Next
()
{
for
it
.
Next
()
{
addr
:=
self
.
trie
.
GetKey
(
it
.
Key
)
addr
:=
self
.
trie
.
GetKey
(
it
.
Key
)
stateObject
,
err
:=
DecodeObject
(
common
.
BytesToAddress
(
addr
),
self
.
db
,
it
.
Value
)
var
data
Account
if
err
!=
nil
{
if
err
:=
rlp
.
DecodeBytes
(
it
.
Value
,
&
data
);
err
!=
nil
{
panic
(
err
)
panic
(
err
)
}
}
account
:=
Account
{
obj
:=
NewObject
(
common
.
BytesToAddress
(
addr
),
data
,
nil
)
Balance
:
stateObject
.
balance
.
String
(),
account
:=
DumpAccount
{
Nonce
:
stateObject
.
nonce
,
Balance
:
data
.
Balance
.
String
(),
Root
:
common
.
Bytes2Hex
(
stateObject
.
Root
()),
Nonce
:
data
.
Nonce
,
CodeHash
:
common
.
Bytes2Hex
(
stateObject
.
codeHash
),
Root
:
common
.
Bytes2Hex
(
data
.
Root
[
:
]),
Code
:
common
.
Bytes2Hex
(
stateObject
.
Code
()),
CodeHash
:
common
.
Bytes2Hex
(
data
.
CodeHash
),
Code
:
common
.
Bytes2Hex
(
obj
.
Code
(
self
.
db
)),
Storage
:
make
(
map
[
string
]
string
),
Storage
:
make
(
map
[
string
]
string
),
}
}
storageIt
:=
stateObject
.
trie
.
Iterator
()
storageIt
:=
obj
.
getTrie
(
self
.
db
)
.
Iterator
()
for
storageIt
.
Next
()
{
for
storageIt
.
Next
()
{
account
.
Storage
[
common
.
Bytes2Hex
(
self
.
trie
.
GetKey
(
storageIt
.
Key
))]
=
common
.
Bytes2Hex
(
storageIt
.
Value
)
account
.
Storage
[
common
.
Bytes2Hex
(
self
.
trie
.
GetKey
(
storageIt
.
Key
))]
=
common
.
Bytes2Hex
(
storageIt
.
Value
)
}
}
world
.
Accounts
[
common
.
Bytes2Hex
(
addr
)]
=
account
dump
.
Accounts
[
common
.
Bytes2Hex
(
addr
)]
=
account
}
}
return
world
return
dump
}
}
func
(
self
*
StateDB
)
Dump
()
[]
byte
{
func
(
self
*
StateDB
)
Dump
()
[]
byte
{
...
@@ -76,12 +78,3 @@ func (self *StateDB) Dump() []byte {
...
@@ -76,12 +78,3 @@ func (self *StateDB) Dump() []byte {
return
json
return
json
}
}
// Debug stuff
func
(
self
*
StateObject
)
CreateOutputForDiff
()
{
fmt
.
Printf
(
"%x %x %x %x
\n
"
,
self
.
Address
(),
self
.
Root
(),
self
.
balance
.
Bytes
(),
self
.
nonce
)
it
:=
self
.
trie
.
Iterator
()
for
it
.
Next
()
{
fmt
.
Printf
(
"%x %x
\n
"
,
it
.
Key
,
it
.
Value
)
}
}
core/state/managed_state.go
View file @
2e14aff8
...
@@ -33,14 +33,14 @@ type ManagedState struct {
...
@@ -33,14 +33,14 @@ type ManagedState struct {
mu
sync
.
RWMutex
mu
sync
.
RWMutex
accounts
map
[
string
]
*
account
accounts
map
[
common
.
Address
]
*
account
}
}
// ManagedState returns a new managed state with the statedb as it's backing layer
// ManagedState returns a new managed state with the statedb as it's backing layer
func
ManageState
(
statedb
*
StateDB
)
*
ManagedState
{
func
ManageState
(
statedb
*
StateDB
)
*
ManagedState
{
return
&
ManagedState
{
return
&
ManagedState
{
StateDB
:
statedb
.
Copy
(),
StateDB
:
statedb
.
Copy
(),
accounts
:
make
(
map
[
string
]
*
account
),
accounts
:
make
(
map
[
common
.
Address
]
*
account
),
}
}
}
}
...
@@ -103,7 +103,7 @@ func (ms *ManagedState) SetNonce(addr common.Address, nonce uint64) {
...
@@ -103,7 +103,7 @@ func (ms *ManagedState) SetNonce(addr common.Address, nonce uint64) {
so
:=
ms
.
GetOrNewStateObject
(
addr
)
so
:=
ms
.
GetOrNewStateObject
(
addr
)
so
.
SetNonce
(
nonce
)
so
.
SetNonce
(
nonce
)
ms
.
accounts
[
addr
.
Str
()
]
=
newAccount
(
so
)
ms
.
accounts
[
addr
]
=
newAccount
(
so
)
}
}
// HasAccount returns whether the given address is managed or not
// HasAccount returns whether the given address is managed or not
...
@@ -114,29 +114,28 @@ func (ms *ManagedState) HasAccount(addr common.Address) bool {
...
@@ -114,29 +114,28 @@ func (ms *ManagedState) HasAccount(addr common.Address) bool {
}
}
func
(
ms
*
ManagedState
)
hasAccount
(
addr
common
.
Address
)
bool
{
func
(
ms
*
ManagedState
)
hasAccount
(
addr
common
.
Address
)
bool
{
_
,
ok
:=
ms
.
accounts
[
addr
.
Str
()
]
_
,
ok
:=
ms
.
accounts
[
addr
]
return
ok
return
ok
}
}
// populate the managed state
// populate the managed state
func
(
ms
*
ManagedState
)
getAccount
(
addr
common
.
Address
)
*
account
{
func
(
ms
*
ManagedState
)
getAccount
(
addr
common
.
Address
)
*
account
{
straddr
:=
addr
.
Str
()
if
account
,
ok
:=
ms
.
accounts
[
addr
];
!
ok
{
if
account
,
ok
:=
ms
.
accounts
[
straddr
];
!
ok
{
so
:=
ms
.
GetOrNewStateObject
(
addr
)
so
:=
ms
.
GetOrNewStateObject
(
addr
)
ms
.
accounts
[
str
addr
]
=
newAccount
(
so
)
ms
.
accounts
[
addr
]
=
newAccount
(
so
)
}
else
{
}
else
{
// Always make sure the state account nonce isn't actually higher
// Always make sure the state account nonce isn't actually higher
// than the tracked one.
// than the tracked one.
so
:=
ms
.
StateDB
.
GetStateObject
(
addr
)
so
:=
ms
.
StateDB
.
GetStateObject
(
addr
)
if
so
!=
nil
&&
uint64
(
len
(
account
.
nonces
))
+
account
.
nstart
<
so
.
nonce
{
if
so
!=
nil
&&
uint64
(
len
(
account
.
nonces
))
+
account
.
nstart
<
so
.
Nonce
()
{
ms
.
accounts
[
str
addr
]
=
newAccount
(
so
)
ms
.
accounts
[
addr
]
=
newAccount
(
so
)
}
}
}
}
return
ms
.
accounts
[
str
addr
]
return
ms
.
accounts
[
addr
]
}
}
func
newAccount
(
so
*
StateObject
)
*
account
{
func
newAccount
(
so
*
StateObject
)
*
account
{
return
&
account
{
so
,
so
.
nonce
,
nil
}
return
&
account
{
so
,
so
.
Nonce
()
,
nil
}
}
}
core/state/managed_state_test.go
View file @
2e14aff8
...
@@ -29,11 +29,12 @@ func create() (*ManagedState, *account) {
...
@@ -29,11 +29,12 @@ func create() (*ManagedState, *account) {
db
,
_
:=
ethdb
.
NewMemDatabase
()
db
,
_
:=
ethdb
.
NewMemDatabase
()
statedb
,
_
:=
New
(
common
.
Hash
{},
db
)
statedb
,
_
:=
New
(
common
.
Hash
{},
db
)
ms
:=
ManageState
(
statedb
)
ms
:=
ManageState
(
statedb
)
so
:=
&
StateObject
{
address
:
addr
,
nonce
:
100
}
so
:=
&
StateObject
{
address
:
addr
}
ms
.
StateDB
.
stateObjects
[
addr
.
Str
()]
=
so
so
.
SetNonce
(
100
)
ms
.
accounts
[
addr
.
Str
()]
=
newAccount
(
so
)
ms
.
StateDB
.
stateObjects
[
addr
]
=
so
ms
.
accounts
[
addr
]
=
newAccount
(
so
)
return
ms
,
ms
.
accounts
[
addr
.
Str
()
]
return
ms
,
ms
.
accounts
[
addr
]
}
}
func
TestNewNonce
(
t
*
testing
.
T
)
{
func
TestNewNonce
(
t
*
testing
.
T
)
{
...
@@ -92,7 +93,7 @@ func TestRemoteNonceChange(t *testing.T) {
...
@@ -92,7 +93,7 @@ func TestRemoteNonceChange(t *testing.T) {
account
.
nonces
=
append
(
account
.
nonces
,
nn
...
)
account
.
nonces
=
append
(
account
.
nonces
,
nn
...
)
nonce
:=
ms
.
NewNonce
(
addr
)
nonce
:=
ms
.
NewNonce
(
addr
)
ms
.
StateDB
.
stateObjects
[
addr
.
Str
()]
.
n
once
=
200
ms
.
StateDB
.
stateObjects
[
addr
]
.
data
.
N
once
=
200
nonce
=
ms
.
NewNonce
(
addr
)
nonce
=
ms
.
NewNonce
(
addr
)
if
nonce
!=
200
{
if
nonce
!=
200
{
t
.
Error
(
"expected nonce after remote update to be"
,
201
,
"got"
,
nonce
)
t
.
Error
(
"expected nonce after remote update to be"
,
201
,
"got"
,
nonce
)
...
@@ -100,7 +101,7 @@ func TestRemoteNonceChange(t *testing.T) {
...
@@ -100,7 +101,7 @@ func TestRemoteNonceChange(t *testing.T) {
ms
.
NewNonce
(
addr
)
ms
.
NewNonce
(
addr
)
ms
.
NewNonce
(
addr
)
ms
.
NewNonce
(
addr
)
ms
.
NewNonce
(
addr
)
ms
.
NewNonce
(
addr
)
ms
.
StateDB
.
stateObjects
[
addr
.
Str
()]
.
n
once
=
200
ms
.
StateDB
.
stateObjects
[
addr
]
.
data
.
N
once
=
200
nonce
=
ms
.
NewNonce
(
addr
)
nonce
=
ms
.
NewNonce
(
addr
)
if
nonce
!=
204
{
if
nonce
!=
204
{
t
.
Error
(
"expected nonce after remote update to be"
,
201
,
"got"
,
nonce
)
t
.
Error
(
"expected nonce after remote update to be"
,
201
,
"got"
,
nonce
)
...
...
core/state/state_object.go
View file @
2e14aff8
...
@@ -57,108 +57,163 @@ func (self Storage) Copy() Storage {
...
@@ -57,108 +57,163 @@ func (self Storage) Copy() Storage {
return
cpy
return
cpy
}
}
// StateObject represents an Ethereum account which is being modified.
//
// The usage pattern is as follows:
// First you need to obtain a state object.
// Account values can be accessed and modified through the object.
// Finally, call CommitTrie to write the modified storage trie into a database.
type
StateObject
struct
{
type
StateObject
struct
{
db
trie
.
Database
// State database for storing state changes
address
common
.
Address
// Ethereum address of this account
trie
*
trie
.
SecureTrie
data
Account
// Address belonging to this account
// DB error.
address
common
.
Address
// State objects are used by the consensus core and VM which are
// The balance of the account
// unable to deal with database-level errors. Any error that occurs
balance
*
big
.
Int
// during a database read is memoized here and will eventually be returned
// The nonce of the account
// by StateDB.Commit.
nonce
uint64
dbErr
error
// The code hash if code is present (i.e. a contract)
codeHash
[]
byte
// Write caches.
// The code for this account
trie
*
trie
.
SecureTrie
// storage trie, which becomes non-nil on first access
code
Code
code
Code
// contract bytecode, which gets set when code is loaded
// Cached storage (flushed when updated)
storage
Storage
// Cached storage (flushed when updated)
storage
Storage
// Cache flags.
// Mark for deletion
// When an object is marked for deletion it will be delete from the trie
// When an object is marked for deletion it will be delete from the trie
// during the "update" phase of the state transition
// during the "update" phase of the state transition
dirtyCode
bool
// true if the code was updated
remove
bool
remove
bool
deleted
bool
deleted
bool
dirty
bool
onDirty
func
(
addr
common
.
Address
)
// Callback method to mark a state object newly dirty
}
// Account is the Ethereum consensus representation of accounts.
// These objects are stored in the main account trie.
type
Account
struct
{
Nonce
uint64
Balance
*
big
.
Int
Root
common
.
Hash
// merkle root of the storage trie
CodeHash
[]
byte
codeSize
*
int
}
}
func
NewStateObject
(
address
common
.
Address
,
db
trie
.
Database
)
*
StateObject
{
// NewObject creates a state object.
object
:=
&
StateObject
{
func
NewObject
(
address
common
.
Address
,
data
Account
,
onDirty
func
(
addr
common
.
Address
))
*
StateObject
{
db
:
db
,
if
data
.
Balance
==
nil
{
address
:
address
,
data
.
Balance
=
new
(
big
.
Int
)
balance
:
new
(
big
.
Int
),
}
dirty
:
true
,
if
data
.
CodeHash
==
nil
{
codeHash
:
emptyCodeHash
,
data
.
CodeHash
=
emptyCodeHash
storage
:
make
(
Storage
),
}
}
object
.
trie
,
_
=
trie
.
NewSecure
(
common
.
Hash
{},
db
)
return
&
StateObject
{
address
:
address
,
data
:
data
,
storage
:
make
(
Storage
),
onDirty
:
onDirty
}
return
object
}
}
func
(
self
*
StateObject
)
MarkForDeletion
()
{
// EncodeRLP implements rlp.Encoder.
self
.
remove
=
true
func
(
c
*
StateObject
)
EncodeRLP
(
w
io
.
Writer
)
error
{
self
.
dirty
=
true
return
rlp
.
Encode
(
w
,
c
.
data
)
}
if
glog
.
V
(
logger
.
Core
)
{
// setError remembers the first non-nil error it is called with.
glog
.
Infof
(
"%x: #%d %v X
\n
"
,
self
.
Address
(),
self
.
nonce
,
self
.
balance
)
func
(
self
*
StateObject
)
setError
(
err
error
)
{
if
self
.
dbErr
==
nil
{
self
.
dbErr
=
err
}
}
}
}
func
(
c
*
StateObject
)
getAddr
(
addr
common
.
Hash
)
common
.
Hash
{
func
(
self
*
StateObject
)
MarkForDeletion
()
{
var
ret
[]
byte
self
.
remove
=
true
rlp
.
DecodeBytes
(
c
.
trie
.
Get
(
addr
[
:
]),
&
ret
)
if
self
.
onDirty
!=
nil
{
return
common
.
BytesToHash
(
ret
)
self
.
onDirty
(
self
.
Address
())
self
.
onDirty
=
nil
}
if
glog
.
V
(
logger
.
Core
)
{
glog
.
Infof
(
"%x: #%d %v X
\n
"
,
self
.
Address
(),
self
.
Nonce
(),
self
.
Balance
())
}
}
}
func
(
c
*
StateObject
)
setAddr
(
addr
,
value
common
.
Hash
)
{
func
(
c
*
StateObject
)
getTrie
(
db
trie
.
Database
)
*
trie
.
SecureTrie
{
v
,
err
:=
rlp
.
EncodeToBytes
(
bytes
.
TrimLeft
(
value
[
:
],
"
\x00
"
))
if
c
.
trie
==
nil
{
var
err
error
c
.
trie
,
err
=
trie
.
NewSecure
(
c
.
data
.
Root
,
db
)
if
err
!=
nil
{
if
err
!=
nil
{
// if RLPing failed we better panic and not fail silently. This would be considered a consensus issue
c
.
trie
,
_
=
trie
.
NewSecure
(
common
.
Hash
{},
db
)
panic
(
err
)
c
.
setError
(
fmt
.
Errorf
(
"can't create storage trie: %v"
,
err
)
)
}
}
c
.
trie
.
Update
(
addr
[
:
],
v
)
}
}
return
c
.
trie
func
(
self
*
StateObject
)
Storage
()
Storage
{
return
self
.
storage
}
}
func
(
self
*
StateObject
)
GetState
(
key
common
.
Hash
)
common
.
Hash
{
// GetState returns a value in account storage.
func
(
self
*
StateObject
)
GetState
(
db
trie
.
Database
,
key
common
.
Hash
)
common
.
Hash
{
value
,
exists
:=
self
.
storage
[
key
]
value
,
exists
:=
self
.
storage
[
key
]
if
!
exists
{
if
exists
{
value
=
self
.
getAddr
(
key
)
return
value
}
// Load from DB in case it is missing.
tr
:=
self
.
getTrie
(
db
)
var
ret
[]
byte
rlp
.
DecodeBytes
(
tr
.
Get
(
key
[
:
]),
&
ret
)
value
=
common
.
BytesToHash
(
ret
)
if
(
value
!=
common
.
Hash
{})
{
if
(
value
!=
common
.
Hash
{})
{
self
.
storage
[
key
]
=
value
self
.
storage
[
key
]
=
value
}
}
}
return
value
return
value
}
}
// SetState updates a value in account storage.
func
(
self
*
StateObject
)
SetState
(
key
,
value
common
.
Hash
)
{
func
(
self
*
StateObject
)
SetState
(
key
,
value
common
.
Hash
)
{
self
.
storage
[
key
]
=
value
self
.
storage
[
key
]
=
value
self
.
dirty
=
true
if
self
.
onDirty
!=
nil
{
self
.
onDirty
(
self
.
Address
())
self
.
onDirty
=
nil
}
}
}
// Update updates the current cached storage to the trie
// updateTrie writes cached storage modifications into the object's storage trie.
func
(
self
*
StateObject
)
Update
()
{
func
(
self
*
StateObject
)
updateTrie
(
db
trie
.
Database
)
{
tr
:=
self
.
getTrie
(
db
)
for
key
,
value
:=
range
self
.
storage
{
for
key
,
value
:=
range
self
.
storage
{
if
(
value
==
common
.
Hash
{})
{
if
(
value
==
common
.
Hash
{})
{
self
.
trie
.
Delete
(
key
[
:
])
tr
.
Delete
(
key
[
:
])
continue
continue
}
}
self
.
setAddr
(
key
,
value
)
// Encoding []byte cannot fail, ok to ignore the error.
v
,
_
:=
rlp
.
EncodeToBytes
(
bytes
.
TrimLeft
(
value
[
:
],
"
\x00
"
))
tr
.
Update
(
key
[
:
],
v
)
}
}
}
}
// UpdateRoot sets the trie root to the current root hash of
func
(
self
*
StateObject
)
UpdateRoot
(
db
trie
.
Database
)
{
self
.
updateTrie
(
db
)
self
.
data
.
Root
=
self
.
trie
.
Hash
()
}
// CommitTrie the storage trie of the object to dwb.
// This updates the trie root.
func
(
self
*
StateObject
)
CommitTrie
(
db
trie
.
Database
,
dbw
trie
.
DatabaseWriter
)
error
{
self
.
updateTrie
(
db
)
if
self
.
dbErr
!=
nil
{
fmt
.
Println
(
"dbErr:"
,
self
.
dbErr
)
return
self
.
dbErr
}
root
,
err
:=
self
.
trie
.
CommitTo
(
dbw
)
if
err
==
nil
{
self
.
data
.
Root
=
root
}
return
err
}
func
(
c
*
StateObject
)
AddBalance
(
amount
*
big
.
Int
)
{
func
(
c
*
StateObject
)
AddBalance
(
amount
*
big
.
Int
)
{
if
amount
.
Cmp
(
common
.
Big0
)
==
0
{
if
amount
.
Cmp
(
common
.
Big0
)
==
0
{
return
return
}
}
c
.
SetBalance
(
new
(
big
.
Int
)
.
Add
(
c
.
balance
,
amount
))
c
.
SetBalance
(
new
(
big
.
Int
)
.
Add
(
c
.
Balance
()
,
amount
))
if
glog
.
V
(
logger
.
Core
)
{
if
glog
.
V
(
logger
.
Core
)
{
glog
.
Infof
(
"%x: #%d %v (+ %v)
\n
"
,
c
.
Address
(),
c
.
nonce
,
c
.
balance
,
amount
)
glog
.
Infof
(
"%x: #%d %v (+ %v)
\n
"
,
c
.
Address
(),
c
.
Nonce
(),
c
.
Balance
()
,
amount
)
}
}
}
}
...
@@ -166,37 +221,32 @@ func (c *StateObject) SubBalance(amount *big.Int) {
...
@@ -166,37 +221,32 @@ func (c *StateObject) SubBalance(amount *big.Int) {
if
amount
.
Cmp
(
common
.
Big0
)
==
0
{
if
amount
.
Cmp
(
common
.
Big0
)
==
0
{
return
return
}
}
c
.
SetBalance
(
new
(
big
.
Int
)
.
Sub
(
c
.
balance
,
amount
))
c
.
SetBalance
(
new
(
big
.
Int
)
.
Sub
(
c
.
Balance
()
,
amount
))
if
glog
.
V
(
logger
.
Core
)
{
if
glog
.
V
(
logger
.
Core
)
{
glog
.
Infof
(
"%x: #%d %v (- %v)
\n
"
,
c
.
Address
(),
c
.
nonce
,
c
.
balance
,
amount
)
glog
.
Infof
(
"%x: #%d %v (- %v)
\n
"
,
c
.
Address
(),
c
.
Nonce
(),
c
.
Balance
()
,
amount
)
}
}
}
}
func
(
c
*
StateObject
)
SetBalance
(
amount
*
big
.
Int
)
{
func
(
self
*
StateObject
)
SetBalance
(
amount
*
big
.
Int
)
{
c
.
balance
=
amount
self
.
data
.
Balance
=
amount
c
.
dirty
=
true
if
self
.
onDirty
!=
nil
{
}
self
.
onDirty
(
self
.
Address
())
self
.
onDirty
=
nil
func
(
c
*
StateObject
)
St
()
Storage
{
}
return
c
.
storage
}
}
// Return the gas back to the origin. Used by the Virtual machine or Closures
// Return the gas back to the origin. Used by the Virtual machine or Closures
func
(
c
*
StateObject
)
ReturnGas
(
gas
,
price
*
big
.
Int
)
{}
func
(
c
*
StateObject
)
ReturnGas
(
gas
,
price
*
big
.
Int
)
{}
func
(
self
*
StateObject
)
Copy
()
*
StateObject
{
func
(
self
*
StateObject
)
Copy
(
db
trie
.
Database
,
onDirty
func
(
addr
common
.
Address
))
*
StateObject
{
stateObject
:=
NewStateObject
(
self
.
Address
(),
self
.
db
)
stateObject
:=
NewObject
(
self
.
address
,
self
.
data
,
onDirty
)
stateObject
.
balance
.
Set
(
self
.
balance
)
stateObject
.
codeHash
=
common
.
CopyBytes
(
self
.
codeHash
)
stateObject
.
nonce
=
self
.
nonce
stateObject
.
trie
=
self
.
trie
stateObject
.
trie
=
self
.
trie
stateObject
.
code
=
self
.
code
stateObject
.
code
=
self
.
code
stateObject
.
storage
=
self
.
storage
.
Copy
()
stateObject
.
storage
=
self
.
storage
.
Copy
()
stateObject
.
remove
=
self
.
remove
stateObject
.
remove
=
self
.
remove
stateObject
.
dirty
=
self
.
dirty
stateObject
.
dirty
Code
=
self
.
dirtyCode
stateObject
.
deleted
=
self
.
deleted
stateObject
.
deleted
=
self
.
deleted
return
stateObject
return
stateObject
}
}
...
@@ -204,40 +254,66 @@ func (self *StateObject) Copy() *StateObject {
...
@@ -204,40 +254,66 @@ func (self *StateObject) Copy() *StateObject {
// Attribute accessors
// Attribute accessors
//
//
func
(
self
*
StateObject
)
Balance
()
*
big
.
Int
{
return
self
.
balance
}
// Returns the address of the contract/account
// Returns the address of the contract/account
func
(
c
*
StateObject
)
Address
()
common
.
Address
{
func
(
c
*
StateObject
)
Address
()
common
.
Address
{
return
c
.
address
return
c
.
address
}
}
func
(
self
*
StateObject
)
Trie
()
*
trie
.
SecureTrie
{
// Code returns the contract code associated with this object, if any.
return
self
.
trie
func
(
self
*
StateObject
)
Code
(
db
trie
.
Database
)
[]
byte
{
}
if
self
.
code
!=
nil
{
return
self
.
code
func
(
self
*
StateObject
)
Root
()
[]
byte
{
}
return
self
.
trie
.
Root
()
if
bytes
.
Equal
(
self
.
CodeHash
(),
emptyCodeHash
)
{
return
nil
}
code
,
err
:=
db
.
Get
(
self
.
CodeHash
())
if
err
!=
nil
{
self
.
setError
(
fmt
.
Errorf
(
"can't load code hash %x: %v"
,
self
.
CodeHash
(),
err
))
}
self
.
code
=
code
return
code
}
}
func
(
self
*
StateObject
)
Code
()
[]
byte
{
// CodeSize returns the size of the contract code associated with this object.
return
self
.
code
func
(
self
*
StateObject
)
CodeSize
(
db
trie
.
Database
)
int
{
if
self
.
data
.
codeSize
==
nil
{
self
.
data
.
codeSize
=
new
(
int
)
*
self
.
data
.
codeSize
=
len
(
self
.
Code
(
db
))
}
return
*
self
.
data
.
codeSize
}
}
func
(
self
*
StateObject
)
SetCode
(
code
[]
byte
)
{
func
(
self
*
StateObject
)
SetCode
(
code
[]
byte
)
{
self
.
code
=
code
self
.
code
=
code
self
.
codeHash
=
crypto
.
Keccak256
(
code
)
self
.
data
.
CodeHash
=
crypto
.
Keccak256
(
code
)
self
.
dirty
=
true
self
.
data
.
codeSize
=
new
(
int
)
*
self
.
data
.
codeSize
=
len
(
code
)
self
.
dirtyCode
=
true
if
self
.
onDirty
!=
nil
{
self
.
onDirty
(
self
.
Address
())
self
.
onDirty
=
nil
}
}
}
func
(
self
*
StateObject
)
SetNonce
(
nonce
uint64
)
{
func
(
self
*
StateObject
)
SetNonce
(
nonce
uint64
)
{
self
.
nonce
=
nonce
self
.
data
.
Nonce
=
nonce
self
.
dirty
=
true
if
self
.
onDirty
!=
nil
{
self
.
onDirty
(
self
.
Address
())
self
.
onDirty
=
nil
}
}
func
(
self
*
StateObject
)
CodeHash
()
[]
byte
{
return
self
.
data
.
CodeHash
}
func
(
self
*
StateObject
)
Balance
()
*
big
.
Int
{
return
self
.
data
.
Balance
}
}
func
(
self
*
StateObject
)
Nonce
()
uint64
{
func
(
self
*
StateObject
)
Nonce
()
uint64
{
return
self
.
n
once
return
self
.
data
.
N
once
}
}
// Never called, but must be present to allow StateObject to be used
// Never called, but must be present to allow StateObject to be used
...
@@ -262,39 +338,3 @@ func (self *StateObject) ForEachStorage(cb func(key, value common.Hash) bool) {
...
@@ -262,39 +338,3 @@ func (self *StateObject) ForEachStorage(cb func(key, value common.Hash) bool) {
}
}
}
}
}
}
type
extStateObject
struct
{
Nonce
uint64
Balance
*
big
.
Int
Root
common
.
Hash
CodeHash
[]
byte
}
// EncodeRLP implements rlp.Encoder.
func
(
c
*
StateObject
)
EncodeRLP
(
w
io
.
Writer
)
error
{
return
rlp
.
Encode
(
w
,
[]
interface
{}{
c
.
nonce
,
c
.
balance
,
c
.
Root
(),
c
.
codeHash
})
}
// DecodeObject decodes an RLP-encoded state object.
func
DecodeObject
(
address
common
.
Address
,
db
trie
.
Database
,
data
[]
byte
)
(
*
StateObject
,
error
)
{
var
(
obj
=
&
StateObject
{
address
:
address
,
db
:
db
,
storage
:
make
(
Storage
)}
ext
extStateObject
err
error
)
if
err
=
rlp
.
DecodeBytes
(
data
,
&
ext
);
err
!=
nil
{
return
nil
,
err
}
if
obj
.
trie
,
err
=
trie
.
NewSecure
(
ext
.
Root
,
db
);
err
!=
nil
{
return
nil
,
err
}
if
!
bytes
.
Equal
(
ext
.
CodeHash
,
emptyCodeHash
)
{
if
obj
.
code
,
err
=
db
.
Get
(
ext
.
CodeHash
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"can't get code for hash %x: %v"
,
ext
.
CodeHash
,
err
)
}
}
obj
.
nonce
=
ext
.
Nonce
obj
.
balance
=
ext
.
Balance
obj
.
codeHash
=
ext
.
CodeHash
return
obj
,
nil
}
core/state/state_test.go
View file @
2e14aff8
...
@@ -146,23 +146,23 @@ func TestSnapshot2(t *testing.T) {
...
@@ -146,23 +146,23 @@ func TestSnapshot2(t *testing.T) {
// db, trie are already non-empty values
// db, trie are already non-empty values
so0
:=
state
.
GetStateObject
(
stateobjaddr0
)
so0
:=
state
.
GetStateObject
(
stateobjaddr0
)
so0
.
balance
=
big
.
NewInt
(
42
)
so0
.
SetBalance
(
big
.
NewInt
(
42
)
)
so0
.
nonce
=
43
so0
.
SetNonce
(
43
)
so0
.
SetCode
([]
byte
{
'c'
,
'a'
,
'f'
,
'e'
})
so0
.
SetCode
([]
byte
{
'c'
,
'a'
,
'f'
,
'e'
})
so0
.
remove
=
false
so0
.
remove
=
false
so0
.
deleted
=
false
so0
.
deleted
=
false
so0
.
dirty
=
true
state
.
SetStateObject
(
so0
)
state
.
SetStateObject
(
so0
)
state
.
Commit
()
root
,
_
:=
state
.
Commit
()
state
.
Reset
(
root
)
// and one with deleted == true
// and one with deleted == true
so1
:=
state
.
GetStateObject
(
stateobjaddr1
)
so1
:=
state
.
GetStateObject
(
stateobjaddr1
)
so1
.
balance
=
big
.
NewInt
(
52
)
so1
.
SetBalance
(
big
.
NewInt
(
52
)
)
so1
.
nonce
=
53
so1
.
SetNonce
(
53
)
so1
.
SetCode
([]
byte
{
'c'
,
'a'
,
'f'
,
'e'
,
'2'
})
so1
.
SetCode
([]
byte
{
'c'
,
'a'
,
'f'
,
'e'
,
'2'
})
so1
.
remove
=
true
so1
.
remove
=
true
so1
.
deleted
=
true
so1
.
deleted
=
true
so1
.
dirty
=
true
state
.
SetStateObject
(
so1
)
state
.
SetStateObject
(
so1
)
so1
=
state
.
GetStateObject
(
stateobjaddr1
)
so1
=
state
.
GetStateObject
(
stateobjaddr1
)
...
@@ -174,41 +174,50 @@ func TestSnapshot2(t *testing.T) {
...
@@ -174,41 +174,50 @@ func TestSnapshot2(t *testing.T) {
state
.
Set
(
snapshot
)
state
.
Set
(
snapshot
)
so0Restored
:=
state
.
GetStateObject
(
stateobjaddr0
)
so0Restored
:=
state
.
GetStateObject
(
stateobjaddr0
)
so0Restored
.
GetState
(
storageaddr
)
// Update lazily-loaded values before comparing.
so1Restored
:=
state
.
GetStateObject
(
stateobjaddr1
)
so0Restored
.
GetState
(
db
,
storageaddr
)
so0Restored
.
Code
(
db
)
// non-deleted is equal (restored)
// non-deleted is equal (restored)
compareStateObjects
(
so0Restored
,
so0
,
t
)
compareStateObjects
(
so0Restored
,
so0
,
t
)
// deleted should be nil, both before and after restore of state copy
// deleted should be nil, both before and after restore of state copy
so1Restored
:=
state
.
GetStateObject
(
stateobjaddr1
)
if
so1Restored
!=
nil
{
if
so1Restored
!=
nil
{
t
.
Fatalf
(
"deleted object not nil after restoring snapshot
"
)
t
.
Fatalf
(
"deleted object not nil after restoring snapshot
: %+v"
,
so1Restored
)
}
}
}
}
func
compareStateObjects
(
so0
,
so1
*
StateObject
,
t
*
testing
.
T
)
{
func
compareStateObjects
(
so0
,
so1
*
StateObject
,
t
*
testing
.
T
)
{
if
so0
.
address
!=
so1
.
address
{
if
so0
.
Address
()
!=
so1
.
Address
()
{
t
.
Fatalf
(
"Address mismatch: have %v, want %v"
,
so0
.
address
,
so1
.
address
)
t
.
Fatalf
(
"Address mismatch: have %v, want %v"
,
so0
.
address
,
so1
.
address
)
}
}
if
so0
.
balance
.
Cmp
(
so1
.
balance
)
!=
0
{
if
so0
.
Balance
()
.
Cmp
(
so1
.
Balance
())
!=
0
{
t
.
Fatalf
(
"Balance mismatch: have %v, want %v"
,
so0
.
balance
,
so1
.
balance
)
t
.
Fatalf
(
"Balance mismatch: have %v, want %v"
,
so0
.
Balance
(),
so1
.
Balance
())
}
if
so0
.
Nonce
()
!=
so1
.
Nonce
()
{
t
.
Fatalf
(
"Nonce mismatch: have %v, want %v"
,
so0
.
Nonce
(),
so1
.
Nonce
())
}
}
if
so0
.
nonce
!=
so1
.
nonce
{
if
so0
.
data
.
Root
!=
so1
.
data
.
Root
{
t
.
Fatalf
(
"Nonce mismatch: have %v, want %v"
,
so0
.
nonce
,
so1
.
nonce
)
t
.
Errorf
(
"Root mismatch: have %x, want %x"
,
so0
.
data
.
Root
[
:
],
so1
.
data
.
Root
[
:
]
)
}
}
if
!
bytes
.
Equal
(
so0
.
codeHash
,
so1
.
codeHash
)
{
if
!
bytes
.
Equal
(
so0
.
CodeHash
(),
so1
.
CodeHash
()
)
{
t
.
Fatalf
(
"CodeHash mismatch: have %v, want %v"
,
so0
.
codeHash
,
so1
.
codeHash
)
t
.
Fatalf
(
"CodeHash mismatch: have %v, want %v"
,
so0
.
CodeHash
(),
so1
.
CodeHash
()
)
}
}
if
!
bytes
.
Equal
(
so0
.
code
,
so1
.
code
)
{
if
!
bytes
.
Equal
(
so0
.
code
,
so1
.
code
)
{
t
.
Fatalf
(
"Code mismatch: have %v, want %v"
,
so0
.
code
,
so1
.
code
)
t
.
Fatalf
(
"Code mismatch: have %v, want %v"
,
so0
.
code
,
so1
.
code
)
}
}
if
len
(
so1
.
storage
)
!=
len
(
so0
.
storage
)
{
t
.
Errorf
(
"Storage size mismatch: have %d, want %d"
,
len
(
so1
.
storage
),
len
(
so0
.
storage
))
}
for
k
,
v
:=
range
so1
.
storage
{
for
k
,
v
:=
range
so1
.
storage
{
if
so0
.
storage
[
k
]
!=
v
{
if
so0
.
storage
[
k
]
!=
v
{
t
.
Fatalf
(
"Storage key %s
mismatch: have %v, want %v"
,
k
,
so0
.
storage
[
k
],
v
)
t
.
Errorf
(
"Storage key %x
mismatch: have %v, want %v"
,
k
,
so0
.
storage
[
k
],
v
)
}
}
}
}
for
k
,
v
:=
range
so0
.
storage
{
for
k
,
v
:=
range
so0
.
storage
{
if
so1
.
storage
[
k
]
!=
v
{
if
so1
.
storage
[
k
]
!=
v
{
t
.
Fatalf
(
"Storage key %s
mismatch: have %v, want none."
,
k
,
v
)
t
.
Errorf
(
"Storage key %x
mismatch: have %v, want none."
,
k
,
v
)
}
}
}
}
...
@@ -218,7 +227,4 @@ func compareStateObjects(so0, so1 *StateObject, t *testing.T) {
...
@@ -218,7 +227,4 @@ func compareStateObjects(so0, so1 *StateObject, t *testing.T) {
if
so0
.
deleted
!=
so1
.
deleted
{
if
so0
.
deleted
!=
so1
.
deleted
{
t
.
Fatalf
(
"Deleted mismatch: have %v, want %v"
,
so0
.
deleted
,
so1
.
deleted
)
t
.
Fatalf
(
"Deleted mismatch: have %v, want %v"
,
so0
.
deleted
,
so1
.
deleted
)
}
}
if
so0
.
dirty
!=
so1
.
dirty
{
t
.
Fatalf
(
"Dirty mismatch: have %v, want %v"
,
so0
.
dirty
,
so1
.
dirty
)
}
}
}
core/state/statedb.go
View file @
2e14aff8
...
@@ -43,8 +43,14 @@ type StateDB struct {
...
@@ -43,8 +43,14 @@ type StateDB struct {
db
ethdb
.
Database
db
ethdb
.
Database
trie
*
trie
.
SecureTrie
trie
*
trie
.
SecureTrie
stateObjects
map
[
string
]
*
StateObject
// This map caches canon state accounts.
all
map
[
common
.
Address
]
Account
// This map holds 'live' objects, which will get modified while processing a state transition.
stateObjects
map
[
common
.
Address
]
*
StateObject
stateObjectsDirty
map
[
common
.
Address
]
struct
{}
// The refund counter, also used by state transitioning.
refund
*
big
.
Int
refund
*
big
.
Int
thash
,
bhash
common
.
Hash
thash
,
bhash
common
.
Hash
...
@@ -62,7 +68,9 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
...
@@ -62,7 +68,9 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
return
&
StateDB
{
return
&
StateDB
{
db
:
db
,
db
:
db
,
trie
:
tr
,
trie
:
tr
,
stateObjects
:
make
(
map
[
string
]
*
StateObject
),
all
:
make
(
map
[
common
.
Address
]
Account
),
stateObjects
:
make
(
map
[
common
.
Address
]
*
StateObject
),
stateObjectsDirty
:
make
(
map
[
common
.
Address
]
struct
{}),
refund
:
new
(
big
.
Int
),
refund
:
new
(
big
.
Int
),
logs
:
make
(
map
[
common
.
Hash
]
vm
.
Logs
),
logs
:
make
(
map
[
common
.
Hash
]
vm
.
Logs
),
},
nil
},
nil
...
@@ -71,19 +79,21 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
...
@@ -71,19 +79,21 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
// Reset clears out all emphemeral state objects from the state db, but keeps
// Reset clears out all emphemeral state objects from the state db, but keeps
// the underlying state trie to avoid reloading data for the next operations.
// the underlying state trie to avoid reloading data for the next operations.
func
(
self
*
StateDB
)
Reset
(
root
common
.
Hash
)
error
{
func
(
self
*
StateDB
)
Reset
(
root
common
.
Hash
)
error
{
var
(
tr
,
err
:=
trie
.
NewSecure
(
root
,
self
.
db
)
err
error
if
err
!=
nil
{
tr
=
self
.
trie
)
if
self
.
trie
.
Hash
()
!=
root
{
if
tr
,
err
=
trie
.
NewSecure
(
root
,
self
.
db
);
err
!=
nil
{
return
err
return
err
}
}
all
:=
self
.
all
if
self
.
trie
.
Hash
()
!=
root
{
// The root has changed, invalidate canon state.
all
=
make
(
map
[
common
.
Address
]
Account
)
}
}
*
self
=
StateDB
{
*
self
=
StateDB
{
db
:
self
.
db
,
db
:
self
.
db
,
trie
:
tr
,
trie
:
tr
,
stateObjects
:
make
(
map
[
string
]
*
StateObject
),
all
:
all
,
stateObjects
:
make
(
map
[
common
.
Address
]
*
StateObject
),
stateObjectsDirty
:
make
(
map
[
common
.
Address
]
struct
{}),
refund
:
new
(
big
.
Int
),
refund
:
new
(
big
.
Int
),
logs
:
make
(
map
[
common
.
Hash
]
vm
.
Logs
),
logs
:
make
(
map
[
common
.
Hash
]
vm
.
Logs
),
}
}
...
@@ -137,7 +147,7 @@ func (self *StateDB) GetAccount(addr common.Address) vm.Account {
...
@@ -137,7 +147,7 @@ func (self *StateDB) GetAccount(addr common.Address) vm.Account {
func
(
self
*
StateDB
)
GetBalance
(
addr
common
.
Address
)
*
big
.
Int
{
func
(
self
*
StateDB
)
GetBalance
(
addr
common
.
Address
)
*
big
.
Int
{
stateObject
:=
self
.
GetStateObject
(
addr
)
stateObject
:=
self
.
GetStateObject
(
addr
)
if
stateObject
!=
nil
{
if
stateObject
!=
nil
{
return
stateObject
.
balance
return
stateObject
.
Balance
()
}
}
return
common
.
Big0
return
common
.
Big0
...
@@ -146,7 +156,7 @@ func (self *StateDB) GetBalance(addr common.Address) *big.Int {
...
@@ -146,7 +156,7 @@ func (self *StateDB) GetBalance(addr common.Address) *big.Int {
func
(
self
*
StateDB
)
GetNonce
(
addr
common
.
Address
)
uint64
{
func
(
self
*
StateDB
)
GetNonce
(
addr
common
.
Address
)
uint64
{
stateObject
:=
self
.
GetStateObject
(
addr
)
stateObject
:=
self
.
GetStateObject
(
addr
)
if
stateObject
!=
nil
{
if
stateObject
!=
nil
{
return
stateObject
.
nonce
return
stateObject
.
Nonce
()
}
}
return
StartingNonce
return
StartingNonce
...
@@ -155,18 +165,24 @@ func (self *StateDB) GetNonce(addr common.Address) uint64 {
...
@@ -155,18 +165,24 @@ func (self *StateDB) GetNonce(addr common.Address) uint64 {
func
(
self
*
StateDB
)
GetCode
(
addr
common
.
Address
)
[]
byte
{
func
(
self
*
StateDB
)
GetCode
(
addr
common
.
Address
)
[]
byte
{
stateObject
:=
self
.
GetStateObject
(
addr
)
stateObject
:=
self
.
GetStateObject
(
addr
)
if
stateObject
!=
nil
{
if
stateObject
!=
nil
{
return
stateObject
.
code
return
stateObject
.
Code
(
self
.
db
)
}
}
return
nil
return
nil
}
}
func
(
self
*
StateDB
)
GetCodeSize
(
addr
common
.
Address
)
int
{
stateObject
:=
self
.
GetStateObject
(
addr
)
if
stateObject
!=
nil
{
return
stateObject
.
CodeSize
(
self
.
db
)
}
return
0
}
func
(
self
*
StateDB
)
GetState
(
a
common
.
Address
,
b
common
.
Hash
)
common
.
Hash
{
func
(
self
*
StateDB
)
GetState
(
a
common
.
Address
,
b
common
.
Hash
)
common
.
Hash
{
stateObject
:=
self
.
GetStateObject
(
a
)
stateObject
:=
self
.
GetStateObject
(
a
)
if
stateObject
!=
nil
{
if
stateObject
!=
nil
{
return
stateObject
.
GetState
(
b
)
return
stateObject
.
GetState
(
self
.
db
,
b
)
}
}
return
common
.
Hash
{}
return
common
.
Hash
{}
}
}
...
@@ -214,8 +230,7 @@ func (self *StateDB) Delete(addr common.Address) bool {
...
@@ -214,8 +230,7 @@ func (self *StateDB) Delete(addr common.Address) bool {
stateObject
:=
self
.
GetStateObject
(
addr
)
stateObject
:=
self
.
GetStateObject
(
addr
)
if
stateObject
!=
nil
{
if
stateObject
!=
nil
{
stateObject
.
MarkForDeletion
()
stateObject
.
MarkForDeletion
()
stateObject
.
balance
=
new
(
big
.
Int
)
stateObject
.
data
.
Balance
=
new
(
big
.
Int
)
return
true
return
true
}
}
...
@@ -242,35 +257,47 @@ func (self *StateDB) DeleteStateObject(stateObject *StateObject) {
...
@@ -242,35 +257,47 @@ func (self *StateDB) DeleteStateObject(stateObject *StateObject) {
addr
:=
stateObject
.
Address
()
addr
:=
stateObject
.
Address
()
self
.
trie
.
Delete
(
addr
[
:
])
self
.
trie
.
Delete
(
addr
[
:
])
//delete(self.stateObjects, addr.Str())
}
}
// Retrieve a state object given my the address.
Nil if not found
// Retrieve a state object given my the address.
Returns nil if not found.
func
(
self
*
StateDB
)
GetStateObject
(
addr
common
.
Address
)
(
stateObject
*
StateObject
)
{
func
(
self
*
StateDB
)
GetStateObject
(
addr
common
.
Address
)
(
stateObject
*
StateObject
)
{
stateObject
=
self
.
stateObjects
[
addr
.
Str
()]
// Prefer 'live' objects.
if
stateObject
!=
nil
{
if
obj
:=
self
.
stateObjects
[
addr
];
obj
!=
nil
{
if
stateObject
.
deleted
{
if
obj
.
deleted
{
stateObject
=
nil
return
nil
}
return
obj
}
}
return
stateObject
// Use cached account data from the canon state if possible.
if
data
,
ok
:=
self
.
all
[
addr
];
ok
{
obj
:=
NewObject
(
addr
,
data
,
self
.
MarkStateObjectDirty
)
self
.
SetStateObject
(
obj
)
return
obj
}
}
data
:=
self
.
trie
.
Get
(
addr
[
:
])
// Load the object from the database.
if
len
(
data
)
==
0
{
enc
:=
self
.
trie
.
Get
(
addr
[
:
])
if
len
(
enc
)
==
0
{
return
nil
return
nil
}
}
stateObject
,
err
:=
DecodeObject
(
addr
,
self
.
db
,
data
)
var
data
Account
if
err
!=
nil
{
if
err
:=
rlp
.
DecodeBytes
(
enc
,
&
data
);
err
!=
nil
{
glog
.
Errorf
(
"can't decode object at %x: %v"
,
addr
[
:
],
err
)
glog
.
Errorf
(
"can't decode object at %x: %v"
,
addr
[
:
],
err
)
return
nil
return
nil
}
}
self
.
SetStateObject
(
stateObject
)
// Update the all cache. Content in DB always corresponds
return
stateObject
// to the current head state so this is ok to do here.
// The object we just loaded has no storage trie and code yet.
self
.
all
[
addr
]
=
data
// Insert into the live set.
obj
:=
NewObject
(
addr
,
data
,
self
.
MarkStateObjectDirty
)
self
.
SetStateObject
(
obj
)
return
obj
}
}
func
(
self
*
StateDB
)
SetStateObject
(
object
*
StateObject
)
{
func
(
self
*
StateDB
)
SetStateObject
(
object
*
StateObject
)
{
self
.
stateObjects
[
object
.
Address
()
.
Str
()
]
=
object
self
.
stateObjects
[
object
.
Address
()]
=
object
}
}
// Retrieve a state object or create a new state object if nil
// Retrieve a state object or create a new state object if nil
...
@@ -288,15 +315,19 @@ func (self *StateDB) newStateObject(addr common.Address) *StateObject {
...
@@ -288,15 +315,19 @@ func (self *StateDB) newStateObject(addr common.Address) *StateObject {
if
glog
.
V
(
logger
.
Core
)
{
if
glog
.
V
(
logger
.
Core
)
{
glog
.
Infof
(
"(+) %x
\n
"
,
addr
)
glog
.
Infof
(
"(+) %x
\n
"
,
addr
)
}
}
obj
:=
NewObject
(
addr
,
Account
{},
self
.
MarkStateObjectDirty
)
obj
.
SetNonce
(
StartingNonce
)
// sets the object to dirty
self
.
stateObjects
[
addr
]
=
obj
return
obj
}
stateObject
:=
NewStateObject
(
addr
,
self
.
db
)
// MarkStateObjectDirty adds the specified object to the dirty map to avoid costly
stateObject
.
SetNonce
(
StartingNonce
)
// state object cache iteration to find a handful of modified ones.
self
.
stateObjects
[
addr
.
Str
()]
=
stateObject
func
(
self
*
StateDB
)
MarkStateObjectDirty
(
addr
common
.
Address
)
{
self
.
stateObjectsDirty
[
addr
]
=
struct
{}{}
return
stateObject
}
}
// Creates creates a new state object and takes ownership.
This is different from "NewStateObject"
// Creates creates a new state object and takes ownership.
func
(
self
*
StateDB
)
CreateStateObject
(
addr
common
.
Address
)
*
StateObject
{
func
(
self
*
StateDB
)
CreateStateObject
(
addr
common
.
Address
)
*
StateObject
{
// Get previous (if any)
// Get previous (if any)
so
:=
self
.
GetStateObject
(
addr
)
so
:=
self
.
GetStateObject
(
addr
)
...
@@ -305,7 +336,7 @@ func (self *StateDB) CreateStateObject(addr common.Address) *StateObject {
...
@@ -305,7 +336,7 @@ func (self *StateDB) CreateStateObject(addr common.Address) *StateObject {
// If it existed set the balance to the new account
// If it existed set the balance to the new account
if
so
!=
nil
{
if
so
!=
nil
{
newSo
.
balance
=
so
.
b
alance
newSo
.
data
.
Balance
=
so
.
data
.
B
alance
}
}
return
newSo
return
newSo
...
@@ -320,29 +351,34 @@ func (self *StateDB) CreateAccount(addr common.Address) vm.Account {
...
@@ -320,29 +351,34 @@ func (self *StateDB) CreateAccount(addr common.Address) vm.Account {
//
//
func
(
self
*
StateDB
)
Copy
()
*
StateDB
{
func
(
self
*
StateDB
)
Copy
()
*
StateDB
{
// ignore error - we assume state-to-be-copied always exists
// Copy all the basic fields, initialize the memory ones
state
,
_
:=
New
(
common
.
Hash
{},
self
.
db
)
state
:=
&
StateDB
{
state
.
trie
=
self
.
trie
db
:
self
.
db
,
for
k
,
stateObject
:=
range
self
.
stateObjects
{
trie
:
self
.
trie
,
if
stateObject
.
dirty
{
all
:
self
.
all
,
state
.
stateObjects
[
k
]
=
stateObject
.
Copy
()
stateObjects
:
make
(
map
[
common
.
Address
]
*
StateObject
,
len
(
self
.
stateObjectsDirty
)),
}
stateObjectsDirty
:
make
(
map
[
common
.
Address
]
struct
{},
len
(
self
.
stateObjectsDirty
)),
refund
:
new
(
big
.
Int
)
.
Set
(
self
.
refund
),
logs
:
make
(
map
[
common
.
Hash
]
vm
.
Logs
,
len
(
self
.
logs
)),
logSize
:
self
.
logSize
,
}
// Copy the dirty states and logs
for
addr
,
_
:=
range
self
.
stateObjectsDirty
{
state
.
stateObjects
[
addr
]
=
self
.
stateObjects
[
addr
]
.
Copy
(
self
.
db
,
state
.
MarkStateObjectDirty
)
state
.
stateObjectsDirty
[
addr
]
=
struct
{}{}
}
}
state
.
refund
.
Set
(
self
.
refund
)
for
hash
,
logs
:=
range
self
.
logs
{
for
hash
,
logs
:=
range
self
.
logs
{
state
.
logs
[
hash
]
=
make
(
vm
.
Logs
,
len
(
logs
))
state
.
logs
[
hash
]
=
make
(
vm
.
Logs
,
len
(
logs
))
copy
(
state
.
logs
[
hash
],
logs
)
copy
(
state
.
logs
[
hash
],
logs
)
}
}
state
.
logSize
=
self
.
logSize
return
state
return
state
}
}
func
(
self
*
StateDB
)
Set
(
state
*
StateDB
)
{
func
(
self
*
StateDB
)
Set
(
state
*
StateDB
)
{
self
.
trie
=
state
.
trie
self
.
trie
=
state
.
trie
self
.
stateObjects
=
state
.
stateObjects
self
.
stateObjects
=
state
.
stateObjects
self
.
stateObjectsDirty
=
state
.
stateObjectsDirty
self
.
all
=
state
.
all
self
.
refund
=
state
.
refund
self
.
refund
=
state
.
refund
self
.
logs
=
state
.
logs
self
.
logs
=
state
.
logs
...
@@ -358,16 +394,15 @@ func (self *StateDB) GetRefund() *big.Int {
...
@@ -358,16 +394,15 @@ func (self *StateDB) GetRefund() *big.Int {
// goes into transaction receipts.
// goes into transaction receipts.
func
(
s
*
StateDB
)
IntermediateRoot
()
common
.
Hash
{
func
(
s
*
StateDB
)
IntermediateRoot
()
common
.
Hash
{
s
.
refund
=
new
(
big
.
Int
)
s
.
refund
=
new
(
big
.
Int
)
for
_
,
stateObject
:=
range
s
.
stateObjects
{
for
addr
,
_
:=
range
s
.
stateObjectsDirty
{
if
stateObject
.
dirty
{
stateObject
:=
s
.
stateObjects
[
addr
]
if
stateObject
.
remove
{
if
stateObject
.
remove
{
s
.
DeleteStateObject
(
stateObject
)
s
.
DeleteStateObject
(
stateObject
)
}
else
{
}
else
{
stateObject
.
Update
(
)
stateObject
.
UpdateRoot
(
s
.
db
)
s
.
UpdateStateObject
(
stateObject
)
s
.
UpdateStateObject
(
stateObject
)
}
}
}
}
}
return
s
.
trie
.
Hash
()
return
s
.
trie
.
Hash
()
}
}
...
@@ -380,15 +415,15 @@ func (s *StateDB) DeleteSuicides() {
...
@@ -380,15 +415,15 @@ func (s *StateDB) DeleteSuicides() {
// Reset refund so that any used-gas calculations can use
// Reset refund so that any used-gas calculations can use
// this method.
// this method.
s
.
refund
=
new
(
big
.
Int
)
s
.
refund
=
new
(
big
.
Int
)
for
_
,
stateObject
:=
range
s
.
stateObjects
{
for
addr
,
_
:=
range
s
.
stateObjectsDirty
{
if
stateObject
.
dirty
{
stateObject
:=
s
.
stateObjects
[
addr
]
// If the object has been removed by a suicide
// If the object has been removed by a suicide
// flag the object as deleted.
// flag the object as deleted.
if
stateObject
.
remove
{
if
stateObject
.
remove
{
stateObject
.
deleted
=
true
stateObject
.
deleted
=
true
}
}
stateObject
.
dirty
=
false
delete
(
s
.
stateObjectsDirty
,
addr
)
}
}
}
}
}
...
@@ -407,46 +442,44 @@ func (s *StateDB) CommitBatch() (root common.Hash, batch ethdb.Batch) {
...
@@ -407,46 +442,44 @@ func (s *StateDB) CommitBatch() (root common.Hash, batch ethdb.Batch) {
return
root
,
batch
return
root
,
batch
}
}
func
(
s
*
StateDB
)
commit
(
db
trie
.
DatabaseWriter
)
(
common
.
Hash
,
error
)
{
func
(
s
*
StateDB
)
commit
(
db
w
trie
.
DatabaseWriter
)
(
root
common
.
Hash
,
err
error
)
{
s
.
refund
=
new
(
big
.
Int
)
s
.
refund
=
new
(
big
.
Int
)
defer
func
()
{
if
err
!=
nil
{
// Committing failed, any updates to the canon state are invalid.
s
.
all
=
make
(
map
[
common
.
Address
]
Account
)
}
}()
for
_
,
stateObject
:=
range
s
.
stateObjects
{
// Commit objects to the trie.
for
addr
,
stateObject
:=
range
s
.
stateObjects
{
if
stateObject
.
remove
{
if
stateObject
.
remove
{
// If the object has been removed, don't bother syncing it
// If the object has been removed, don't bother syncing it
// and just mark it for deletion in the trie.
// and just mark it for deletion in the trie.
s
.
DeleteStateObject
(
stateObject
)
s
.
DeleteStateObject
(
stateObject
)
}
else
{
delete
(
s
.
all
,
addr
)
}
else
if
_
,
ok
:=
s
.
stateObjectsDirty
[
addr
];
ok
{
// Write any contract code associated with the state object
// Write any contract code associated with the state object
if
len
(
stateObject
.
code
)
>
0
{
if
stateObject
.
code
!=
nil
&&
stateObject
.
dirtyCode
{
if
err
:=
db
.
Put
(
stateObject
.
codeHash
,
stateObject
.
code
);
err
!=
nil
{
if
err
:=
db
w
.
Put
(
stateObject
.
CodeHash
()
,
stateObject
.
code
);
err
!=
nil
{
return
common
.
Hash
{},
err
return
common
.
Hash
{},
err
}
}
stateObject
.
dirtyCode
=
false
}
}
// Write any storage changes in the state object to its trie.
// Write any storage changes in the state object to its storage trie.
stateObject
.
Update
()
if
err
:=
stateObject
.
CommitTrie
(
s
.
db
,
dbw
);
err
!=
nil
{
// Commit the trie of the object to the batch.
// This updates the trie root internally, so
// getting the root hash of the storage trie
// through UpdateStateObject is fast.
if
_
,
err
:=
stateObject
.
trie
.
CommitTo
(
db
);
err
!=
nil
{
return
common
.
Hash
{},
err
return
common
.
Hash
{},
err
}
}
// Update the object in the account trie.
// Update the object in the
main
account trie.
s
.
UpdateStateObject
(
stateObject
)
s
.
UpdateStateObject
(
stateObject
)
s
.
all
[
addr
]
=
stateObject
.
data
}
}
stateObject
.
dirty
=
false
delete
(
s
.
stateObjectsDirty
,
addr
)
}
}
return
s
.
trie
.
CommitTo
(
db
)
// Write trie changes.
return
s
.
trie
.
CommitTo
(
dbw
)
}
}
func
(
self
*
StateDB
)
Refunds
()
*
big
.
Int
{
func
(
self
*
StateDB
)
Refunds
()
*
big
.
Int
{
return
self
.
refund
return
self
.
refund
}
}
// Debug stuff
func
(
self
*
StateDB
)
CreateOutputForDiff
()
{
for
_
,
stateObject
:=
range
self
.
stateObjects
{
stateObject
.
CreateOutputForDiff
()
}
}
core/vm/environment.go
View file @
2e14aff8
...
@@ -94,6 +94,7 @@ type Database interface {
...
@@ -94,6 +94,7 @@ type Database interface {
GetNonce
(
common
.
Address
)
uint64
GetNonce
(
common
.
Address
)
uint64
SetNonce
(
common
.
Address
,
uint64
)
SetNonce
(
common
.
Address
,
uint64
)
GetCodeSize
(
common
.
Address
)
int
GetCode
(
common
.
Address
)
[]
byte
GetCode
(
common
.
Address
)
[]
byte
SetCode
(
common
.
Address
,
[]
byte
)
SetCode
(
common
.
Address
,
[]
byte
)
...
...
core/vm/instructions.go
View file @
2e14aff8
...
@@ -363,7 +363,7 @@ func opCalldataCopy(instr instruction, pc *uint64, env Environment, contract *Co
...
@@ -363,7 +363,7 @@ func opCalldataCopy(instr instruction, pc *uint64, env Environment, contract *Co
func
opExtCodeSize
(
instr
instruction
,
pc
*
uint64
,
env
Environment
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
{
func
opExtCodeSize
(
instr
instruction
,
pc
*
uint64
,
env
Environment
,
contract
*
Contract
,
memory
*
Memory
,
stack
*
Stack
)
{
addr
:=
common
.
BigToAddress
(
stack
.
pop
())
addr
:=
common
.
BigToAddress
(
stack
.
pop
())
l
:=
big
.
NewInt
(
int64
(
len
(
env
.
Db
()
.
GetCode
(
addr
)
)))
l
:=
big
.
NewInt
(
int64
(
env
.
Db
()
.
GetCodeSize
(
addr
)))
stack
.
push
(
l
)
stack
.
push
(
l
)
}
}
...
...
eth/api.go
View file @
2e14aff8
...
@@ -288,14 +288,14 @@ func NewPublicDebugAPI(eth *Ethereum) *PublicDebugAPI {
...
@@ -288,14 +288,14 @@ func NewPublicDebugAPI(eth *Ethereum) *PublicDebugAPI {
}
}
// DumpBlock retrieves the entire state of the database at a given block.
// DumpBlock retrieves the entire state of the database at a given block.
func
(
api
*
PublicDebugAPI
)
DumpBlock
(
number
uint64
)
(
state
.
World
,
error
)
{
func
(
api
*
PublicDebugAPI
)
DumpBlock
(
number
uint64
)
(
state
.
Dump
,
error
)
{
block
:=
api
.
eth
.
BlockChain
()
.
GetBlockByNumber
(
number
)
block
:=
api
.
eth
.
BlockChain
()
.
GetBlockByNumber
(
number
)
if
block
==
nil
{
if
block
==
nil
{
return
state
.
World
{},
fmt
.
Errorf
(
"block #%d not found"
,
number
)
return
state
.
Dump
{},
fmt
.
Errorf
(
"block #%d not found"
,
number
)
}
}
stateDb
,
err
:=
state
.
New
(
block
.
Root
(),
api
.
eth
.
ChainDb
())
stateDb
,
err
:=
state
.
New
(
block
.
Root
(),
api
.
eth
.
ChainDb
())
if
err
!=
nil
{
if
err
!=
nil
{
return
state
.
World
{},
err
return
state
.
Dump
{},
err
}
}
return
stateDb
.
RawDump
(),
nil
return
stateDb
.
RawDump
(),
nil
}
}
...
...
internal/ethapi/api.go
View file @
2e14aff8
...
@@ -1280,8 +1280,8 @@ func (api *PrivateDebugAPI) ChaindbProperty(property string) (string, error) {
...
@@ -1280,8 +1280,8 @@ func (api *PrivateDebugAPI) ChaindbProperty(property string) (string, error) {
}
}
// SetHead rewinds the head of the blockchain to a previous block.
// SetHead rewinds the head of the blockchain to a previous block.
func
(
api
*
PrivateDebugAPI
)
SetHead
(
number
uint64
)
{
func
(
api
*
PrivateDebugAPI
)
SetHead
(
number
rpc
.
HexNumber
)
{
api
.
b
.
SetHead
(
number
)
api
.
b
.
SetHead
(
uint64
(
number
.
Int64
())
)
}
}
// PublicNetAPI offers network related RPC methods
// PublicNetAPI offers network related RPC methods
...
...
light/state_test.go
View file @
2e14aff8
...
@@ -62,7 +62,7 @@ func makeTestState() (common.Hash, ethdb.Database) {
...
@@ -62,7 +62,7 @@ func makeTestState() (common.Hash, ethdb.Database) {
}
}
so
.
AddBalance
(
big
.
NewInt
(
int64
(
i
)))
so
.
AddBalance
(
big
.
NewInt
(
int64
(
i
)))
so
.
SetCode
([]
byte
{
i
,
i
,
i
})
so
.
SetCode
([]
byte
{
i
,
i
,
i
})
so
.
Update
(
)
so
.
Update
Root
(
sdb
)
st
.
UpdateStateObject
(
so
)
st
.
UpdateStateObject
(
so
)
}
}
root
,
_
:=
st
.
Commit
()
root
,
_
:=
st
.
Commit
()
...
...
tests/state_test_util.go
View file @
2e14aff8
...
@@ -97,7 +97,7 @@ func benchStateTest(ruleSet RuleSet, test VmTest, env map[string]string, b *test
...
@@ -97,7 +97,7 @@ func benchStateTest(ruleSet RuleSet, test VmTest, env map[string]string, b *test
db
,
_
:=
ethdb
.
NewMemDatabase
()
db
,
_
:=
ethdb
.
NewMemDatabase
()
statedb
,
_
:=
state
.
New
(
common
.
Hash
{},
db
)
statedb
,
_
:=
state
.
New
(
common
.
Hash
{},
db
)
for
addr
,
account
:=
range
test
.
Pre
{
for
addr
,
account
:=
range
test
.
Pre
{
obj
:=
StateObjectFromAccount
(
db
,
addr
,
account
)
obj
:=
StateObjectFromAccount
(
db
,
addr
,
account
,
statedb
.
MarkStateObjectDirty
)
statedb
.
SetStateObject
(
obj
)
statedb
.
SetStateObject
(
obj
)
for
a
,
v
:=
range
account
.
Storage
{
for
a
,
v
:=
range
account
.
Storage
{
obj
.
SetState
(
common
.
HexToHash
(
a
),
common
.
HexToHash
(
v
))
obj
.
SetState
(
common
.
HexToHash
(
a
),
common
.
HexToHash
(
v
))
...
@@ -136,7 +136,7 @@ func runStateTest(ruleSet RuleSet, test VmTest) error {
...
@@ -136,7 +136,7 @@ func runStateTest(ruleSet RuleSet, test VmTest) error {
db
,
_
:=
ethdb
.
NewMemDatabase
()
db
,
_
:=
ethdb
.
NewMemDatabase
()
statedb
,
_
:=
state
.
New
(
common
.
Hash
{},
db
)
statedb
,
_
:=
state
.
New
(
common
.
Hash
{},
db
)
for
addr
,
account
:=
range
test
.
Pre
{
for
addr
,
account
:=
range
test
.
Pre
{
obj
:=
StateObjectFromAccount
(
db
,
addr
,
account
)
obj
:=
StateObjectFromAccount
(
db
,
addr
,
account
,
statedb
.
MarkStateObjectDirty
)
statedb
.
SetStateObject
(
obj
)
statedb
.
SetStateObject
(
obj
)
for
a
,
v
:=
range
account
.
Storage
{
for
a
,
v
:=
range
account
.
Storage
{
obj
.
SetState
(
common
.
HexToHash
(
a
),
common
.
HexToHash
(
v
))
obj
.
SetState
(
common
.
HexToHash
(
a
),
common
.
HexToHash
(
v
))
...
@@ -187,7 +187,7 @@ func runStateTest(ruleSet RuleSet, test VmTest) error {
...
@@ -187,7 +187,7 @@ func runStateTest(ruleSet RuleSet, test VmTest) error {
}
}
for
addr
,
value
:=
range
account
.
Storage
{
for
addr
,
value
:=
range
account
.
Storage
{
v
:=
obj
.
GetState
(
common
.
HexToHash
(
addr
))
v
:=
statedb
.
GetState
(
obj
.
Address
(),
common
.
HexToHash
(
addr
))
vexp
:=
common
.
HexToHash
(
value
)
vexp
:=
common
.
HexToHash
(
value
)
if
v
!=
vexp
{
if
v
!=
vexp
{
...
...
tests/util.go
View file @
2e14aff8
...
@@ -103,16 +103,17 @@ func (self Log) Topics() [][]byte {
...
@@ -103,16 +103,17 @@ func (self Log) Topics() [][]byte {
return
t
return
t
}
}
func
StateObjectFromAccount
(
db
ethdb
.
Database
,
addr
string
,
account
Account
)
*
state
.
StateObject
{
func
StateObjectFromAccount
(
db
ethdb
.
Database
,
addr
string
,
account
Account
,
onDirty
func
(
common
.
Address
))
*
state
.
StateObject
{
obj
:=
state
.
NewStateObject
(
common
.
HexToAddress
(
addr
),
db
)
obj
.
SetBalance
(
common
.
Big
(
account
.
Balance
))
if
common
.
IsHex
(
account
.
Code
)
{
if
common
.
IsHex
(
account
.
Code
)
{
account
.
Code
=
account
.
Code
[
2
:
]
account
.
Code
=
account
.
Code
[
2
:
]
}
}
obj
.
SetCode
(
common
.
Hex2Bytes
(
account
.
Code
))
code
:=
common
.
Hex2Bytes
(
account
.
Code
)
obj
.
SetNonce
(
common
.
Big
(
account
.
Nonce
)
.
Uint64
())
obj
:=
state
.
NewObject
(
common
.
HexToAddress
(
addr
),
state
.
Account
{
Balance
:
common
.
Big
(
account
.
Balance
),
CodeHash
:
crypto
.
Keccak256
(
code
),
Nonce
:
common
.
Big
(
account
.
Nonce
)
.
Uint64
(),
},
onDirty
)
obj
.
SetCode
(
code
)
return
obj
return
obj
}
}
...
...
tests/vm_test_util.go
View file @
2e14aff8
...
@@ -103,7 +103,7 @@ func benchVmTest(test VmTest, env map[string]string, b *testing.B) {
...
@@ -103,7 +103,7 @@ func benchVmTest(test VmTest, env map[string]string, b *testing.B) {
db
,
_
:=
ethdb
.
NewMemDatabase
()
db
,
_
:=
ethdb
.
NewMemDatabase
()
statedb
,
_
:=
state
.
New
(
common
.
Hash
{},
db
)
statedb
,
_
:=
state
.
New
(
common
.
Hash
{},
db
)
for
addr
,
account
:=
range
test
.
Pre
{
for
addr
,
account
:=
range
test
.
Pre
{
obj
:=
StateObjectFromAccount
(
db
,
addr
,
account
)
obj
:=
StateObjectFromAccount
(
db
,
addr
,
account
,
statedb
.
MarkStateObjectDirty
)
statedb
.
SetStateObject
(
obj
)
statedb
.
SetStateObject
(
obj
)
for
a
,
v
:=
range
account
.
Storage
{
for
a
,
v
:=
range
account
.
Storage
{
obj
.
SetState
(
common
.
HexToHash
(
a
),
common
.
HexToHash
(
v
))
obj
.
SetState
(
common
.
HexToHash
(
a
),
common
.
HexToHash
(
v
))
...
@@ -154,7 +154,7 @@ func runVmTest(test VmTest) error {
...
@@ -154,7 +154,7 @@ func runVmTest(test VmTest) error {
db
,
_
:=
ethdb
.
NewMemDatabase
()
db
,
_
:=
ethdb
.
NewMemDatabase
()
statedb
,
_
:=
state
.
New
(
common
.
Hash
{},
db
)
statedb
,
_
:=
state
.
New
(
common
.
Hash
{},
db
)
for
addr
,
account
:=
range
test
.
Pre
{
for
addr
,
account
:=
range
test
.
Pre
{
obj
:=
StateObjectFromAccount
(
db
,
addr
,
account
)
obj
:=
StateObjectFromAccount
(
db
,
addr
,
account
,
statedb
.
MarkStateObjectDirty
)
statedb
.
SetStateObject
(
obj
)
statedb
.
SetStateObject
(
obj
)
for
a
,
v
:=
range
account
.
Storage
{
for
a
,
v
:=
range
account
.
Storage
{
obj
.
SetState
(
common
.
HexToHash
(
a
),
common
.
HexToHash
(
v
))
obj
.
SetState
(
common
.
HexToHash
(
a
),
common
.
HexToHash
(
v
))
...
@@ -205,11 +205,9 @@ func runVmTest(test VmTest) error {
...
@@ -205,11 +205,9 @@ func runVmTest(test VmTest) error {
if
obj
==
nil
{
if
obj
==
nil
{
continue
continue
}
}
for
addr
,
value
:=
range
account
.
Storage
{
for
addr
,
value
:=
range
account
.
Storage
{
v
:=
obj
.
GetState
(
common
.
HexToHash
(
addr
))
v
:=
statedb
.
GetState
(
obj
.
Address
(),
common
.
HexToHash
(
addr
))
vexp
:=
common
.
HexToHash
(
value
)
vexp
:=
common
.
HexToHash
(
value
)
if
v
!=
vexp
{
if
v
!=
vexp
{
return
fmt
.
Errorf
(
"(%x: %s) storage failed. Expected %x, got %x (%v %v)
\n
"
,
obj
.
Address
()
.
Bytes
()[
0
:
4
],
addr
,
vexp
,
v
,
vexp
.
Big
(),
v
.
Big
())
return
fmt
.
Errorf
(
"(%x: %s) storage failed. Expected %x, got %x (%v %v)
\n
"
,
obj
.
Address
()
.
Bytes
()[
0
:
4
],
addr
,
vexp
,
v
,
vexp
.
Big
(),
v
.
Big
())
}
}
...
...
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