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
d754091a
Unverified
Commit
d754091a
authored
Nov 22, 2019
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core/state/snapshot: unlink snapshots from blocks, quad->linear cleanup
parent
cdf3f016
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
203 additions
and
206 deletions
+203
-206
blockchain.go
core/blockchain.go
+5
-5
accessors_snapshot.go
core/rawdb/accessors_snapshot.go
+19
-21
schema.go
core/rawdb/schema.go
+2
-2
difflayer.go
core/state/snapshot/difflayer.go
+16
-11
difflayer_journal.go
core/state/snapshot/difflayer_journal.go
+4
-21
difflayer_test.go
core/state/snapshot/difflayer_test.go
+21
-35
disklayer.go
core/state/snapshot/disklayer.go
+15
-7
generate.go
core/state/snapshot/generate.go
+5
-6
generate_test.go
core/state/snapshot/generate_test.go
+5
-5
snapshot.go
core/state/snapshot/snapshot.go
+96
-79
snapshot_test.go
core/state/snapshot/snapshot_test.go
+5
-6
statedb.go
core/state/statedb.go
+10
-8
No files found.
core/blockchain.go
View file @
d754091a
...
...
@@ -141,7 +141,7 @@ type BlockChain struct {
cacheConfig
*
CacheConfig
// Cache configuration for pruning
db
ethdb
.
Database
// Low level persistent database to store final content in
snaps
*
snapshot
.
Snapshot
Tree
// Snapshot tree for fast trie leaf access
snaps
*
snapshot
.
Tree
// Snapshot tree for fast trie leaf access
triegc
*
prque
.
Prque
// Priority queue mapping block numbers to tries to gc
gcproc
time
.
Duration
// Accumulates canonical block processing for trie dumping
...
...
@@ -301,7 +301,7 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
}
// Load any existing snapshot, regenerating it if loading failed
head
:=
bc
.
CurrentBlock
()
if
bc
.
snaps
,
err
=
snapshot
.
New
(
bc
.
db
,
"snapshot.rlp"
,
head
.
NumberU64
(),
head
.
Root
());
err
!=
nil
{
if
bc
.
snaps
,
err
=
snapshot
.
New
(
bc
.
db
,
"snapshot.rlp"
,
head
.
Root
());
err
!=
nil
{
return
nil
,
err
}
// Take ownership of this particular state
...
...
core/rawdb/accessors_snapshot.go
View file @
d754091a
...
...
@@ -17,38 +17,36 @@
package
rawdb
import
(
"encoding/binary"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/log"
)
// ReadSnapshot
Block retrieves the number and root of the block whose state is
//
contained in
the persisted snapshot.
func
ReadSnapshot
Block
(
db
ethdb
.
KeyValueReader
)
(
uint64
,
common
.
Hash
)
{
data
,
_
:=
db
.
Get
(
snapshot
Block
Key
)
if
len
(
data
)
!=
8
+
common
.
HashLength
{
return
0
,
common
.
Hash
{}
// ReadSnapshot
Root retrieves the root of the block whose state is contained in
// the persisted snapshot.
func
ReadSnapshot
Root
(
db
ethdb
.
KeyValueReader
)
common
.
Hash
{
data
,
_
:=
db
.
Get
(
snapshot
Root
Key
)
if
len
(
data
)
!=
common
.
HashLength
{
return
common
.
Hash
{}
}
return
binary
.
BigEndian
.
Uint64
(
data
[
:
8
]),
common
.
BytesToHash
(
data
[
8
:
]
)
return
common
.
BytesToHash
(
data
)
}
// WriteSnapshot
Block stores the number and root of the block whose state is
//
contained in
the persisted snapshot.
func
WriteSnapshot
Block
(
db
ethdb
.
KeyValueWriter
,
number
uint64
,
root
common
.
Hash
)
{
if
err
:=
db
.
Put
(
snapshot
BlockKey
,
append
(
encodeBlockNumber
(
number
),
root
.
Bytes
()
...
)
);
err
!=
nil
{
log
.
Crit
(
"Failed to store snaps
not block's number and
root"
,
"err"
,
err
)
// WriteSnapshot
Root stores the root of the block whose state is contained in
// the persisted snapshot.
func
WriteSnapshot
Root
(
db
ethdb
.
KeyValueWriter
,
root
common
.
Hash
)
{
if
err
:=
db
.
Put
(
snapshot
RootKey
,
root
[
:
]
);
err
!=
nil
{
log
.
Crit
(
"Failed to store snaps
hot
root"
,
"err"
,
err
)
}
}
// DeleteSnapshot
Block deletes the number and hash of the block whose state is
//
contained in the persisted snapshot. Since snapshots are not immutable, this
//
method can be used during updates, so a crash or failure will mark the entire
//
snapshot
invalid.
func
DeleteSnapshot
Block
(
db
ethdb
.
KeyValueWriter
)
{
if
err
:=
db
.
Delete
(
snapshot
Block
Key
);
err
!=
nil
{
log
.
Crit
(
"Failed to remove snaps
not block's number and hash
"
,
"err"
,
err
)
// DeleteSnapshot
Root deletes the hash of the block whose state is contained in
//
the persisted snapshot. Since snapshots are not immutable, this method can
//
be used during updates, so a crash or failure will mark the entire snapshot
// invalid.
func
DeleteSnapshot
Root
(
db
ethdb
.
KeyValueWriter
)
{
if
err
:=
db
.
Delete
(
snapshot
Root
Key
);
err
!=
nil
{
log
.
Crit
(
"Failed to remove snaps
hot root
"
,
"err"
,
err
)
}
}
...
...
core/rawdb/schema.go
View file @
d754091a
...
...
@@ -41,8 +41,8 @@ var (
// fastTrieProgressKey tracks the number of trie entries imported during fast sync.
fastTrieProgressKey
=
[]
byte
(
"TrieSync"
)
// snapshot
Block
Key tracks the number and hash of the last snapshot.
snapshot
BlockKey
=
[]
byte
(
"SnapshotBlock
"
)
// snapshot
Root
Key tracks the number and hash of the last snapshot.
snapshot
RootKey
=
[]
byte
(
"SnapshotRoot
"
)
// Data item prefixes (use single byte to avoid mixing data types, avoid `i`, used for indexes).
headerPrefix
=
[]
byte
(
"h"
)
// headerPrefix + num (uint64 big endian) + hash -> header
...
...
core/state/snapshot/difflayer.go
View file @
d754091a
...
...
@@ -36,7 +36,6 @@ type diffLayer struct {
parent
snapshot
// Parent snapshot modified by this one, never nil
memory
uint64
// Approximate guess as to how much memory we use
number
uint64
// Block number to which this snapshot diff belongs to
root
common
.
Hash
// Root hash to which this snapshot diff belongs to
stale
bool
// Signals that the layer became stale (state progressed)
...
...
@@ -50,11 +49,10 @@ type diffLayer struct {
// newDiffLayer creates a new diff on top of an existing snapshot, whether that's a low
// level persistent database or a hierarchical diff already.
func
newDiffLayer
(
parent
snapshot
,
number
uint64
,
root
common
.
Hash
,
accounts
map
[
common
.
Hash
][]
byte
,
storage
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
*
diffLayer
{
func
newDiffLayer
(
parent
snapshot
,
root
common
.
Hash
,
accounts
map
[
common
.
Hash
][]
byte
,
storage
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
*
diffLayer
{
// Create the new layer with some pre-allocated data segments
dl
:=
&
diffLayer
{
parent
:
parent
,
number
:
number
,
root
:
root
,
accountData
:
accounts
,
storageData
:
storage
,
...
...
@@ -63,7 +61,6 @@ func newDiffLayer(parent snapshot, number uint64, root common.Hash, accounts map
for
_
,
data
:=
range
accounts
{
dl
.
memory
+=
uint64
(
len
(
data
))
}
// Fill the storage hashes and sort them for the iterator
dl
.
storageList
=
make
(
map
[
common
.
Hash
][]
common
.
Hash
)
...
...
@@ -93,9 +90,18 @@ func newDiffLayer(parent snapshot, number uint64, root common.Hash, accounts map
return
dl
}
// Info returns the block number and root hash for which this snapshot was made.
func
(
dl
*
diffLayer
)
Info
()
(
uint64
,
common
.
Hash
)
{
return
dl
.
number
,
dl
.
root
// Root returns the root hash for which this snapshot was made.
func
(
dl
*
diffLayer
)
Root
()
common
.
Hash
{
return
dl
.
root
}
// Stale return whether this layer has become stale (was flattened across) or if
// it's still live.
func
(
dl
*
diffLayer
)
Stale
()
bool
{
dl
.
lock
.
RLock
()
defer
dl
.
lock
.
RUnlock
()
return
dl
.
stale
}
// Account directly retrieves the account associated with a particular hash in
...
...
@@ -164,7 +170,7 @@ func (dl *diffLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro
// Update creates a new layer on top of the existing snapshot diff tree with
// the specified data items.
func
(
dl
*
diffLayer
)
Update
(
blockRoot
common
.
Hash
,
accounts
map
[
common
.
Hash
][]
byte
,
storage
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
*
diffLayer
{
return
newDiffLayer
(
dl
,
dl
.
number
+
1
,
blockRoot
,
accounts
,
storage
)
return
newDiffLayer
(
dl
,
blockRoot
,
accounts
,
storage
)
}
// flatten pushes all data from this point downwards, flattening everything into
...
...
@@ -213,7 +219,6 @@ func (dl *diffLayer) flatten() snapshot {
// Return the combo parent
return
&
diffLayer
{
parent
:
parent
.
parent
,
number
:
dl
.
number
,
root
:
dl
.
root
,
storageList
:
parent
.
storageList
,
storageData
:
parent
.
storageData
,
...
...
core/state/snapshot/difflayer_journal.go
View file @
d754091a
...
...
@@ -43,18 +43,12 @@ type journalStorage struct {
// diff and verifying that it can be linked to the requested parent.
func
loadDiffLayer
(
parent
snapshot
,
r
*
rlp
.
Stream
)
(
snapshot
,
error
)
{
// Read the next diff journal entry
var
(
number
uint64
root
common
.
Hash
)
if
err
:=
r
.
Decode
(
&
number
);
err
!=
nil
{
var
root
common
.
Hash
if
err
:=
r
.
Decode
(
&
root
);
err
!=
nil
{
// The first read may fail with EOF, marking the end of the journal
if
err
==
io
.
EOF
{
return
parent
,
nil
}
return
nil
,
fmt
.
Errorf
(
"load diff number: %v"
,
err
)
}
if
err
:=
r
.
Decode
(
&
root
);
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"load diff root: %v"
,
err
)
}
var
accounts
[]
journalAccount
...
...
@@ -77,13 +71,7 @@ func loadDiffLayer(parent snapshot, r *rlp.Stream) (snapshot, error) {
}
storageData
[
entry
.
Hash
]
=
slots
}
// Validate the block number to avoid state corruption
if
parent
,
ok
:=
parent
.
(
*
diffLayer
);
ok
{
if
number
!=
parent
.
number
+
1
{
return
nil
,
fmt
.
Errorf
(
"snapshot chain broken: block #%d after #%d"
,
number
,
parent
.
number
)
}
}
return
loadDiffLayer
(
newDiffLayer
(
parent
,
number
,
root
,
accountData
,
storageData
),
r
)
return
loadDiffLayer
(
newDiffLayer
(
parent
,
root
,
accountData
,
storageData
),
r
)
}
// journal is the internal version of Journal that also returns the journal file
...
...
@@ -113,13 +101,8 @@ func (dl *diffLayer) journal() (io.WriteCloser, error) {
writer
.
Close
()
return
nil
,
ErrSnapshotStale
}
buf
:=
bufio
.
NewWriter
(
writer
)
// Everything below was journalled, persist this layer too
if
err
:=
rlp
.
Encode
(
buf
,
dl
.
number
);
err
!=
nil
{
buf
.
Flush
()
writer
.
Close
()
return
nil
,
err
}
buf
:=
bufio
.
NewWriter
(
writer
)
if
err
:=
rlp
.
Encode
(
buf
,
dl
.
root
);
err
!=
nil
{
buf
.
Flush
()
writer
.
Close
()
...
...
core/state/snapshot/difflayer_test.go
View file @
d754091a
...
...
@@ -61,11 +61,11 @@ func TestMergeBasics(t *testing.T) {
}
}
// Add some (identical) layers on top
parent
:=
newDiffLayer
(
emptyLayer
{},
1
,
common
.
Hash
{},
accounts
,
storage
)
child
:=
newDiffLayer
(
parent
,
1
,
common
.
Hash
{},
accounts
,
storage
)
child
=
newDiffLayer
(
child
,
1
,
common
.
Hash
{},
accounts
,
storage
)
child
=
newDiffLayer
(
child
,
1
,
common
.
Hash
{},
accounts
,
storage
)
child
=
newDiffLayer
(
child
,
1
,
common
.
Hash
{},
accounts
,
storage
)
parent
:=
newDiffLayer
(
emptyLayer
{},
common
.
Hash
{},
accounts
,
storage
)
child
:=
newDiffLayer
(
parent
,
common
.
Hash
{},
accounts
,
storage
)
child
=
newDiffLayer
(
child
,
common
.
Hash
{},
accounts
,
storage
)
child
=
newDiffLayer
(
child
,
common
.
Hash
{},
accounts
,
storage
)
child
=
newDiffLayer
(
child
,
common
.
Hash
{},
accounts
,
storage
)
// And flatten
merged
:=
(
child
.
flatten
())
.
(
*
diffLayer
)
...
...
@@ -122,7 +122,7 @@ func TestMergeDelete(t *testing.T) {
}
// Add some flip-flopping layers on top
parent
:=
newDiffLayer
(
emptyLayer
{},
1
,
common
.
Hash
{},
flip
(),
storage
)
parent
:=
newDiffLayer
(
emptyLayer
{},
common
.
Hash
{},
flip
(),
storage
)
child
:=
parent
.
Update
(
common
.
Hash
{},
flop
(),
storage
)
child
=
child
.
Update
(
common
.
Hash
{},
flip
(),
storage
)
child
=
child
.
Update
(
common
.
Hash
{},
flop
(),
storage
)
...
...
@@ -139,10 +139,6 @@ func TestMergeDelete(t *testing.T) {
// And flatten
merged
:=
(
child
.
flatten
())
.
(
*
diffLayer
)
// check number
if
got
,
exp
:=
merged
.
number
,
child
.
number
;
got
!=
exp
{
t
.
Errorf
(
"merged layer: wrong number - exp %d got %d"
,
exp
,
got
)
}
if
data
,
_
:=
merged
.
Account
(
h1
);
data
==
nil
{
t
.
Errorf
(
"merged layer: expected %x to be non-nil"
,
h1
)
}
...
...
@@ -169,7 +165,7 @@ func TestInsertAndMerge(t *testing.T) {
{
var
accounts
=
make
(
map
[
common
.
Hash
][]
byte
)
var
storage
=
make
(
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
parent
=
newDiffLayer
(
emptyLayer
{},
1
,
common
.
Hash
{},
accounts
,
storage
)
parent
=
newDiffLayer
(
emptyLayer
{},
common
.
Hash
{},
accounts
,
storage
)
}
{
var
accounts
=
make
(
map
[
common
.
Hash
][]
byte
)
...
...
@@ -178,7 +174,7 @@ func TestInsertAndMerge(t *testing.T) {
accstorage
:=
make
(
map
[
common
.
Hash
][]
byte
)
storage
[
acc
]
=
accstorage
storage
[
acc
][
slot
]
=
[]
byte
{
0x01
}
child
=
newDiffLayer
(
parent
,
2
,
common
.
Hash
{},
accounts
,
storage
)
child
=
newDiffLayer
(
parent
,
common
.
Hash
{},
accounts
,
storage
)
}
// And flatten
merged
:=
(
child
.
flatten
())
.
(
*
diffLayer
)
...
...
@@ -200,11 +196,12 @@ func (emptyLayer) Journal() error {
panic
(
"implement me"
)
}
func
(
emptyLayer
)
Info
()
(
uint64
,
common
.
Hash
)
{
return
0
,
common
.
Hash
{}
func
(
emptyLayer
)
Stale
()
bool
{
panic
(
"implement me"
)
}
func
(
emptyLayer
)
Number
()
uint64
{
return
0
func
(
emptyLayer
)
Root
()
common
.
Hash
{
return
common
.
Hash
{}
}
func
(
emptyLayer
)
Account
(
hash
common
.
Hash
)
(
*
Account
,
error
)
{
...
...
@@ -227,8 +224,6 @@ func (emptyLayer) Storage(accountHash, storageHash common.Hash) ([]byte, error)
// BenchmarkSearch-6 500000 3723 ns/op (10k per layer, only top-level RLock()
func
BenchmarkSearch
(
b
*
testing
.
B
)
{
// First, we set up 128 diff layers, with 1K items each
blocknum
:=
uint64
(
0
)
fill
:=
func
(
parent
snapshot
)
*
diffLayer
{
accounts
:=
make
(
map
[
common
.
Hash
][]
byte
)
storage
:=
make
(
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
...
...
@@ -236,10 +231,8 @@ func BenchmarkSearch(b *testing.B) {
for
i
:=
0
;
i
<
10000
;
i
++
{
accounts
[
randomHash
()]
=
randomAccount
()
}
blocknum
++
return
newDiffLayer
(
parent
,
blocknum
,
common
.
Hash
{},
accounts
,
storage
)
return
newDiffLayer
(
parent
,
common
.
Hash
{},
accounts
,
storage
)
}
var
layer
snapshot
layer
=
emptyLayer
{}
for
i
:=
0
;
i
<
128
;
i
++
{
...
...
@@ -261,8 +254,6 @@ func BenchmarkSearch(b *testing.B) {
// BenchmarkSearchSlot-6 100000 14551 ns/op (when checking parent number using atomic)
func
BenchmarkSearchSlot
(
b
*
testing
.
B
)
{
// First, we set up 128 diff layers, with 1K items each
blocknum
:=
uint64
(
0
)
accountKey
:=
common
.
Hash
{}
storageKey
:=
common
.
HexToHash
(
"0x1337"
)
accountRLP
:=
randomAccount
()
...
...
@@ -278,16 +269,13 @@ func BenchmarkSearchSlot(b *testing.B) {
accStorage
[
randomHash
()]
=
value
storage
[
accountKey
]
=
accStorage
}
blocknum
++
return
newDiffLayer
(
parent
,
blocknum
,
common
.
Hash
{},
accounts
,
storage
)
return
newDiffLayer
(
parent
,
common
.
Hash
{},
accounts
,
storage
)
}
var
layer
snapshot
layer
=
emptyLayer
{}
for
i
:=
0
;
i
<
128
;
i
++
{
layer
=
fill
(
layer
)
}
b
.
ResetTimer
()
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
layer
.
Storage
(
accountKey
,
storageKey
)
...
...
@@ -300,7 +288,7 @@ func BenchmarkSearchSlot(b *testing.B) {
// Without sorting and tracking accountlist
// BenchmarkFlatten-6 300 5511511 ns/op
func
BenchmarkFlatten
(
b
*
testing
.
B
)
{
fill
:=
func
(
parent
snapshot
,
blocknum
int
)
*
diffLayer
{
fill
:=
func
(
parent
snapshot
)
*
diffLayer
{
accounts
:=
make
(
map
[
common
.
Hash
][]
byte
)
storage
:=
make
(
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
...
...
@@ -317,7 +305,7 @@ func BenchmarkFlatten(b *testing.B) {
}
storage
[
accountKey
]
=
accStorage
}
return
newDiffLayer
(
parent
,
uint64
(
blocknum
),
common
.
Hash
{},
accounts
,
storage
)
return
newDiffLayer
(
parent
,
common
.
Hash
{},
accounts
,
storage
)
}
b
.
ResetTimer
()
...
...
@@ -327,7 +315,7 @@ func BenchmarkFlatten(b *testing.B) {
var
layer
snapshot
layer
=
emptyLayer
{}
for
i
:=
1
;
i
<
128
;
i
++
{
layer
=
fill
(
layer
,
i
)
layer
=
fill
(
layer
)
}
b
.
StartTimer
()
...
...
@@ -336,7 +324,6 @@ func BenchmarkFlatten(b *testing.B) {
if
!
ok
{
break
}
layer
=
dl
.
flatten
()
}
b
.
StopTimer
()
...
...
@@ -351,7 +338,7 @@ func BenchmarkFlatten(b *testing.B) {
// BenchmarkJournal-6 1 1471373923 ns/ops
// BenchmarkJournal-6 1 1208083335 ns/op // bufio writer
func
BenchmarkJournal
(
b
*
testing
.
B
)
{
fill
:=
func
(
parent
snapshot
,
blocknum
int
)
*
diffLayer
{
fill
:=
func
(
parent
snapshot
)
*
diffLayer
{
accounts
:=
make
(
map
[
common
.
Hash
][]
byte
)
storage
:=
make
(
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
...
...
@@ -368,15 +355,14 @@ func BenchmarkJournal(b *testing.B) {
}
storage
[
accountKey
]
=
accStorage
}
return
newDiffLayer
(
parent
,
uint64
(
blocknum
),
common
.
Hash
{},
accounts
,
storage
)
return
newDiffLayer
(
parent
,
common
.
Hash
{},
accounts
,
storage
)
}
var
layer
snapshot
layer
=
&
diskLayer
{
journal
:
path
.
Join
(
os
.
TempDir
(),
"difflayer_journal.tmp"
),
}
for
i
:=
1
;
i
<
128
;
i
++
{
layer
=
fill
(
layer
,
i
)
layer
=
fill
(
layer
)
}
b
.
ResetTimer
()
...
...
core/state/snapshot/disklayer.go
View file @
d754091a
...
...
@@ -32,16 +32,24 @@ type diskLayer struct {
db
ethdb
.
KeyValueStore
// Key-value store containing the base snapshot
cache
*
bigcache
.
BigCache
// Cache to avoid hitting the disk for direct access
number
uint64
// Block number of the base snapshot
root
common
.
Hash
// Root hash of the base snapshot
stale
bool
// Signals that the layer became stale (state progressed)
lock
sync
.
RWMutex
}
// Info returns the block number and root hash for which this snapshot was made.
func
(
dl
*
diskLayer
)
Info
()
(
uint64
,
common
.
Hash
)
{
return
dl
.
number
,
dl
.
root
// Root returns root hash for which this snapshot was made.
func
(
dl
*
diskLayer
)
Root
()
common
.
Hash
{
return
dl
.
root
}
// Stale return whether this layer has become stale (was flattened across) or if
// it's still live.
func
(
dl
*
diskLayer
)
Stale
()
bool
{
dl
.
lock
.
RLock
()
defer
dl
.
lock
.
RUnlock
()
return
dl
.
stale
}
// Account directly retrieves the account associated with a particular hash in
...
...
@@ -123,7 +131,7 @@ func (dl *diskLayer) Storage(accountHash, storageHash common.Hash) ([]byte, erro
// the specified data items. Note, the maps are retained by the method to avoid
// copying everything.
func
(
dl
*
diskLayer
)
Update
(
blockHash
common
.
Hash
,
accounts
map
[
common
.
Hash
][]
byte
,
storage
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
*
diffLayer
{
return
newDiffLayer
(
dl
,
dl
.
number
+
1
,
blockHash
,
accounts
,
storage
)
return
newDiffLayer
(
dl
,
blockHash
,
accounts
,
storage
)
}
// Journal commits an entire diff hierarchy to disk into a single journal file.
...
...
core/state/snapshot/generate.go
View file @
d754091a
...
...
@@ -85,7 +85,7 @@ func wipeSnapshot(db ethdb.KeyValueStore) error {
}
it
.
Release
()
rawdb
.
DeleteSnapshot
Block
(
batch
)
rawdb
.
DeleteSnapshot
Root
(
batch
)
if
err
:=
batch
.
Write
();
err
!=
nil
{
return
err
}
...
...
@@ -107,7 +107,7 @@ func wipeSnapshot(db ethdb.KeyValueStore) error {
}
// generateSnapshot regenerates a brand new snapshot based on an existing state database and head block.
func
generateSnapshot
(
db
ethdb
.
KeyValueStore
,
journal
string
,
headNumber
uint64
,
headR
oot
common
.
Hash
)
(
snapshot
,
error
)
{
func
generateSnapshot
(
db
ethdb
.
KeyValueStore
,
journal
string
,
r
oot
common
.
Hash
)
(
snapshot
,
error
)
{
// Wipe any previously existing snapshot from the database
if
err
:=
wipeSnapshot
(
db
);
err
!=
nil
{
return
nil
,
err
...
...
@@ -124,7 +124,7 @@ func generateSnapshot(db ethdb.KeyValueStore, journal string, headNumber uint64,
batch
:=
db
.
NewBatch
()
triedb
:=
trie
.
NewDatabase
(
db
)
accTrie
,
err
:=
trie
.
NewSecure
(
headR
oot
,
triedb
)
accTrie
,
err
:=
trie
.
NewSecure
(
r
oot
,
triedb
)
if
err
!=
nil
{
return
nil
,
err
}
...
...
@@ -186,7 +186,7 @@ func generateSnapshot(db ethdb.KeyValueStore, journal string, headNumber uint64,
fmt
.
Printf
(
"Totals: %9s (%d accs, %d nodes) + %9s (%d slots, %d nodes)
\n
"
,
accountSize
.
TerminalString
(),
accountCount
,
accIt
.
Nodes
,
storageSize
.
TerminalString
(),
storageCount
,
storageNodes
)
// Update the snapshot block marker and write any remainder data
rawdb
.
WriteSnapshot
Block
(
batch
,
headNumber
,
headR
oot
)
rawdb
.
WriteSnapshot
Root
(
batch
,
r
oot
)
batch
.
Write
()
batch
.
Reset
()
...
...
@@ -207,7 +207,6 @@ func generateSnapshot(db ethdb.KeyValueStore, journal string, headNumber uint64,
journal
:
journal
,
db
:
db
,
cache
:
cache
,
number
:
headNumber
,
root
:
headRoot
,
root
:
root
,
},
nil
}
core/state/snapshot/generate_test.go
View file @
d754091a
...
...
@@ -47,7 +47,7 @@ func TestWipe(t *testing.T) {
rawdb
.
WriteStorageSnapshot
(
db
,
account
,
randomHash
(),
randomHash
()
.
Bytes
())
}
}
rawdb
.
WriteSnapshot
Block
(
db
,
123
,
randomHash
())
rawdb
.
WriteSnapshot
Root
(
db
,
randomHash
())
// Add some random non-snapshot data too to make wiping harder
for
i
:=
0
;
i
<
65536
;
i
++
{
...
...
@@ -76,8 +76,8 @@ func TestWipe(t *testing.T) {
if
items
!=
128
+
128
*
1024
{
t
.
Fatalf
(
"snapshot size mismatch: have %d, want %d"
,
items
,
128
+
128
*
1024
)
}
if
number
,
hash
:=
rawdb
.
ReadSnapshotBlock
(
db
);
number
!=
123
||
hash
==
(
common
.
Hash
{})
{
t
.
Errorf
(
"snapshot block marker mismatch: have
#%d [%#x], want #%d [<not-nil>]"
,
number
,
hash
,
123
)
if
hash
:=
rawdb
.
ReadSnapshotRoot
(
db
);
hash
==
(
common
.
Hash
{})
{
t
.
Errorf
(
"snapshot block marker mismatch: have
%#x, want <not-nil>"
,
hash
)
}
// Wipe all snapshot entries from the database
if
err
:=
wipeSnapshot
(
db
);
err
!=
nil
{
...
...
@@ -93,8 +93,8 @@ func TestWipe(t *testing.T) {
t
.
Errorf
(
"snapshot entry remained after wipe: %x"
,
key
)
}
}
if
number
,
hash
:=
rawdb
.
ReadSnapshotBlock
(
db
);
number
!=
0
||
hash
!=
(
common
.
Hash
{})
{
t
.
Errorf
(
"snapshot block marker remained after wipe:
#%d [%#x]"
,
number
,
hash
)
if
hash
:=
rawdb
.
ReadSnapshotRoot
(
db
);
hash
!=
(
common
.
Hash
{})
{
t
.
Errorf
(
"snapshot block marker remained after wipe:
%#x"
,
hash
)
}
// Iterate over the database and ensure miscellaneous items are present
items
=
0
...
...
core/state/snapshot/snapshot.go
View file @
d754091a
...
...
@@ -43,12 +43,16 @@ var (
// layer had been invalidated due to the chain progressing forward far enough
// to not maintain the layer's original state.
ErrSnapshotStale
=
errors
.
New
(
"snapshot stale"
)
// errSnapshotCycle is returned if a snapshot is attempted to be inserted
// that forms a cycle in the snapshot tree.
errSnapshotCycle
=
errors
.
New
(
"snapshot cycle"
)
)
// Snapshot represents the functionality supported by a snapshot storage layer.
type
Snapshot
interface
{
//
Info returns the block number and
root hash for which this snapshot was made.
Info
()
(
uint64
,
common
.
Hash
)
//
Root returns the
root hash for which this snapshot was made.
Root
()
common
.
Hash
// Account directly retrieves the account associated with a particular hash in
// the snapshot slim data format.
...
...
@@ -77,6 +81,10 @@ type snapshot interface {
// This is meant to be used during shutdown to persist the snapshot without
// flattening everything down (bad for reorgs).
Journal
()
error
// Stale return whether this layer has become stale (was flattened across) or
// if it's still live.
Stale
()
bool
}
// SnapshotTree is an Ethereum state snapshot tree. It consists of one persistent
...
...
@@ -88,7 +96,7 @@ type snapshot interface {
// The goal of a state snapshot is twofold: to allow direct access to account and
// storage data to avoid expensive multi-level trie lookups; and to allow sorted,
// cheap iteration of the account/storage tries for sync aid.
type
Snapshot
Tree
struct
{
type
Tree
struct
{
layers
map
[
common
.
Hash
]
snapshot
// Collection of all known layers // TODO(karalabe): split Clique overlaps
lock
sync
.
RWMutex
}
...
...
@@ -99,22 +107,21 @@ type SnapshotTree struct {
//
// If the snapshot is missing or inconsistent, the entirety is deleted and will
// be reconstructed from scratch based on the tries in the key-value store.
func
New
(
db
ethdb
.
KeyValueStore
,
journal
string
,
headNumber
uint64
,
headRoot
common
.
Hash
)
(
*
Snapshot
Tree
,
error
)
{
func
New
(
db
ethdb
.
KeyValueStore
,
journal
string
,
root
common
.
Hash
)
(
*
Tree
,
error
)
{
// Attempt to load a previously persisted snapshot
head
,
err
:=
loadSnapshot
(
db
,
journal
,
headNumber
,
headR
oot
)
head
,
err
:=
loadSnapshot
(
db
,
journal
,
r
oot
)
if
err
!=
nil
{
log
.
Warn
(
"Failed to load snapshot, regenerating"
,
"err"
,
err
)
if
head
,
err
=
generateSnapshot
(
db
,
journal
,
headNumber
,
headR
oot
);
err
!=
nil
{
if
head
,
err
=
generateSnapshot
(
db
,
journal
,
r
oot
);
err
!=
nil
{
return
nil
,
err
}
}
// Existing snapshot loaded or one regenerated, seed all the layers
snap
:=
&
Snapshot
Tree
{
snap
:=
&
Tree
{
layers
:
make
(
map
[
common
.
Hash
]
snapshot
),
}
for
head
!=
nil
{
_
,
root
:=
head
.
Info
()
snap
.
layers
[
root
]
=
head
snap
.
layers
[
head
.
Root
()]
=
head
switch
self
:=
head
.
(
type
)
{
case
*
diffLayer
:
...
...
@@ -130,54 +137,57 @@ func New(db ethdb.KeyValueStore, journal string, headNumber uint64, headRoot com
// Snapshot retrieves a snapshot belonging to the given block root, or nil if no
// snapshot is maintained for that block.
func
(
st
*
Snapshot
Tree
)
Snapshot
(
blockRoot
common
.
Hash
)
Snapshot
{
s
t
.
lock
.
RLock
()
defer
s
t
.
lock
.
RUnlock
()
func
(
t
*
Tree
)
Snapshot
(
blockRoot
common
.
Hash
)
Snapshot
{
t
.
lock
.
RLock
()
defer
t
.
lock
.
RUnlock
()
return
s
t
.
layers
[
blockRoot
]
return
t
.
layers
[
blockRoot
]
}
// Update adds a new snapshot into the tree, if that can be linked to an existing
// old parent. It is disallowed to insert a disk layer (the origin of all).
func
(
st
*
SnapshotTree
)
Update
(
blockRoot
common
.
Hash
,
parentRoot
common
.
Hash
,
accounts
map
[
common
.
Hash
][]
byte
,
storage
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
error
{
func
(
t
*
Tree
)
Update
(
blockRoot
common
.
Hash
,
parentRoot
common
.
Hash
,
accounts
map
[
common
.
Hash
][]
byte
,
storage
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
error
{
// Reject noop updates to avoid self-loops in the snapshot tree. This is a
// special case that can only happen for Clique networks where empty blocks
// don't modify the state (0 block subsidy).
//
// Although we could silently ignore this internally, it should be the caller's
// responsibility to avoid even attempting to insert such a snapshot.
if
blockRoot
==
parentRoot
{
return
errSnapshotCycle
}
// Generate a new snapshot on top of the parent
parent
:=
s
t
.
Snapshot
(
parentRoot
)
.
(
snapshot
)
parent
:=
t
.
Snapshot
(
parentRoot
)
.
(
snapshot
)
if
parent
==
nil
{
return
fmt
.
Errorf
(
"parent [%#x] snapshot missing"
,
parentRoot
)
}
snap
:=
parent
.
Update
(
blockRoot
,
accounts
,
storage
)
// Save the new snapshot for later
s
t
.
lock
.
Lock
()
defer
s
t
.
lock
.
Unlock
()
t
.
lock
.
Lock
()
defer
t
.
lock
.
Unlock
()
s
t
.
layers
[
snap
.
root
]
=
snap
t
.
layers
[
snap
.
root
]
=
snap
return
nil
}
// Cap traverses downwards the snapshot tree from a head block hash until the
// number of allowed layers are crossed. All layers beyond the permitted number
// are flattened downwards.
func
(
st
*
SnapshotTree
)
Cap
(
blockR
oot
common
.
Hash
,
layers
int
,
memory
uint64
)
error
{
func
(
t
*
Tree
)
Cap
(
r
oot
common
.
Hash
,
layers
int
,
memory
uint64
)
error
{
// Retrieve the head snapshot to cap from
var
snap
snapshot
if
s
:=
st
.
Snapshot
(
blockRoot
);
s
==
nil
{
return
fmt
.
Errorf
(
"snapshot [%#x] missing"
,
blockRoot
)
}
else
{
snap
=
s
.
(
snapshot
)
snap
:=
t
.
Snapshot
(
root
)
if
snap
==
nil
{
return
fmt
.
Errorf
(
"snapshot [%#x] missing"
,
root
)
}
diff
,
ok
:=
snap
.
(
*
diffLayer
)
if
!
ok
{
return
fmt
.
Errorf
(
"snapshot [%#x] is disk layer"
,
blockR
oot
)
return
fmt
.
Errorf
(
"snapshot [%#x] is disk layer"
,
r
oot
)
}
// Run the internal capping and discard all stale layers
s
t
.
lock
.
Lock
()
defer
s
t
.
lock
.
Unlock
()
t
.
lock
.
Lock
()
defer
t
.
lock
.
Unlock
()
var
(
diskNumber
uint64
diffNumber
uint64
)
// Flattening the bottom-most diff layer requires special casing since there's
// no child to rewire to the grandparent. In that case we can fake a temporary
// child for the capping and then remove it.
...
...
@@ -188,8 +198,9 @@ func (st *SnapshotTree) Cap(blockRoot common.Hash, layers int, memory uint64) er
base
:=
diffToDisk
(
diff
.
flatten
()
.
(
*
diffLayer
))
diff
.
lock
.
RUnlock
()
st
.
layers
[
base
.
root
]
=
base
diskNumber
,
diffNumber
=
base
.
number
,
base
.
number
// Replace the entire snapshot tree with the flat base
t
.
layers
=
map
[
common
.
Hash
]
snapshot
{
base
.
root
:
base
}
return
nil
case
1
:
// If full flattening was requested, flatten the diffs but only merge if the
...
...
@@ -205,59 +216,74 @@ func (st *SnapshotTree) Cap(blockRoot common.Hash, layers int, memory uint64) er
}
diff
.
lock
.
RUnlock
()
// If all diff layers were removed, replace the entire snapshot tree
if
base
!=
nil
{
st
.
layers
[
base
.
root
]
=
base
diskNumber
,
diffNumber
=
base
.
number
,
base
.
number
}
else
{
st
.
layers
[
bottom
.
root
]
=
bottom
diskNumber
,
diffNumber
=
bottom
.
parent
.
(
*
diskLayer
)
.
number
,
bottom
.
number
t
.
layers
=
map
[
common
.
Hash
]
snapshot
{
base
.
root
:
base
}
return
nil
}
// Merge the new aggregated layer into the snapshot tree, clean stales below
t
.
layers
[
bottom
.
root
]
=
bottom
default
:
diskNumber
,
diffNumber
=
st
.
cap
(
diff
,
layers
,
memory
)
// Many layers requested to be retained, cap normally
t
.
cap
(
diff
,
layers
,
memory
)
}
// Remove any layer that is stale or links into a stale layer
children
:=
make
(
map
[
common
.
Hash
][]
common
.
Hash
)
for
root
,
snap
:=
range
t
.
layers
{
if
diff
,
ok
:=
snap
.
(
*
diffLayer
);
ok
{
parent
:=
diff
.
parent
.
Root
()
children
[
parent
]
=
append
(
children
[
parent
],
root
)
}
}
for
root
,
snap
:=
range
st
.
layers
{
if
number
,
_
:=
snap
.
Info
();
number
!=
diskNumber
&&
number
<
diffNumber
{
delete
(
st
.
layers
,
root
)
var
remove
func
(
root
common
.
Hash
)
remove
=
func
(
root
common
.
Hash
)
{
delete
(
t
.
layers
,
root
)
for
_
,
child
:=
range
children
[
root
]
{
remove
(
child
)
}
delete
(
children
,
root
)
}
for
root
,
snap
:=
range
t
.
layers
{
if
snap
.
Stale
()
{
remove
(
root
)
}
}
return
nil
}
// cap traverses downwards the diff tree until the number of allowed layers are
// crossed. All diffs beyond the permitted number are flattened downwards. If
// the layer limit is reached, memory cap is also enforced (but not before). The
// block numbers for the disk layer and first diff layer are returned for GC.
func
(
st
*
SnapshotTree
)
cap
(
diff
*
diffLayer
,
layers
int
,
memory
uint64
)
(
uint64
,
uint64
)
{
// crossed. All diffs beyond the permitted number are flattened downwards. If the
// layer limit is reached, memory cap is also enforced (but not before).
func
(
t
*
Tree
)
cap
(
diff
*
diffLayer
,
layers
int
,
memory
uint64
)
{
// Dive until we run out of layers or reach the persistent database
for
;
layers
>
2
;
layers
--
{
// If we still have diff layers below, continue down
if
parent
,
ok
:=
diff
.
parent
.
(
*
diffLayer
);
ok
{
diff
=
parent
}
else
{
// Diff stack too shallow, return
block numbers
without modifications
return
diff
.
parent
.
(
*
diskLayer
)
.
number
,
diff
.
number
// Diff stack too shallow, return without modifications
return
}
}
// We're out of layers, flatten anything below, stopping if it's the disk or if
// the memory limit is not yet exceeded.
switch
parent
:=
diff
.
parent
.
(
type
)
{
case
*
diskLayer
:
return
parent
.
number
,
diff
.
number
return
case
*
diffLayer
:
// Flatten the parent into the grandparent. The flattening internally obtains a
// write lock on grandparent.
flattened
:=
parent
.
flatten
()
.
(
*
diffLayer
)
s
t
.
layers
[
flattened
.
root
]
=
flattened
t
.
layers
[
flattened
.
root
]
=
flattened
diff
.
lock
.
Lock
()
defer
diff
.
lock
.
Unlock
()
diff
.
parent
=
flattened
if
flattened
.
memory
<
memory
{
diskNumber
,
_
:=
flattened
.
parent
.
Info
()
return
diskNumber
,
flattened
.
number
return
}
default
:
panic
(
fmt
.
Sprintf
(
"unknown data layer: %T"
,
parent
))
...
...
@@ -269,10 +295,8 @@ func (st *SnapshotTree) cap(diff *diffLayer, layers int, memory uint64) (uint64,
base
:=
diffToDisk
(
bottom
)
bottom
.
lock
.
RUnlock
()
s
t
.
layers
[
base
.
root
]
=
base
t
.
layers
[
base
.
root
]
=
base
diff
.
parent
=
base
return
base
.
number
,
diff
.
number
}
// diffToDisk merges a bottom-most diff into the persistent disk layer underneath
...
...
@@ -284,7 +308,7 @@ func diffToDisk(bottom *diffLayer) *diskLayer {
)
// Start by temporarily deleting the current snapshot block marker. This
// ensures that in the case of a crash, the entire snapshot is invalidated.
rawdb
.
DeleteSnapshot
Block
(
batch
)
rawdb
.
DeleteSnapshot
Root
(
batch
)
// Mark the original base as stale as we're going to create a new wrapper
base
.
lock
.
Lock
()
...
...
@@ -341,13 +365,12 @@ func diffToDisk(bottom *diffLayer) *diskLayer {
}
}
// Update the snapshot block marker and write any remainder data
rawdb
.
WriteSnapshot
Block
(
batch
,
bottom
.
number
,
bottom
.
root
)
rawdb
.
WriteSnapshot
Root
(
batch
,
bottom
.
root
)
if
err
:=
batch
.
Write
();
err
!=
nil
{
log
.
Crit
(
"Failed to write leftover snapshot"
,
"err"
,
err
)
}
return
&
diskLayer
{
root
:
bottom
.
root
,
number
:
bottom
.
number
,
cache
:
base
.
cache
,
db
:
base
.
db
,
journal
:
base
.
journal
,
...
...
@@ -357,27 +380,25 @@ func diffToDisk(bottom *diffLayer) *diskLayer {
// Journal commits an entire diff hierarchy to disk into a single journal file.
// This is meant to be used during shutdown to persist the snapshot without
// flattening everything down (bad for reorgs).
func
(
st
*
Snapshot
Tree
)
Journal
(
blockRoot
common
.
Hash
)
error
{
// Retrieve the head snapshot to journal from
var
snap
snapshot
if
s
:=
st
.
Snapshot
(
blockRoot
);
s
==
nil
{
func
(
t
*
Tree
)
Journal
(
blockRoot
common
.
Hash
)
error
{
// Retrieve the head snapshot to journal from
var snap snapshot
snap
:=
t
.
Snapshot
(
blockRoot
)
if
s
nap
==
nil
{
return
fmt
.
Errorf
(
"snapshot [%#x] missing"
,
blockRoot
)
}
else
{
snap
=
s
.
(
snapshot
)
}
// Run the journaling
s
t
.
lock
.
Lock
()
defer
s
t
.
lock
.
Unlock
()
t
.
lock
.
Lock
()
defer
t
.
lock
.
Unlock
()
return
snap
.
Journal
()
return
snap
.
(
snapshot
)
.
Journal
()
}
// loadSnapshot loads a pre-existing state snapshot backed by a key-value store.
func
loadSnapshot
(
db
ethdb
.
KeyValueStore
,
journal
string
,
headNumber
uint64
,
headR
oot
common
.
Hash
)
(
snapshot
,
error
)
{
func
loadSnapshot
(
db
ethdb
.
KeyValueStore
,
journal
string
,
r
oot
common
.
Hash
)
(
snapshot
,
error
)
{
// Retrieve the block number and hash of the snapshot, failing if no snapshot
// is present in the database (or crashed mid-update).
number
,
root
:=
rawdb
.
ReadSnapshotBlock
(
db
)
if
r
oot
==
(
common
.
Hash
{})
{
baseRoot
:=
rawdb
.
ReadSnapshotRoot
(
db
)
if
baseR
oot
==
(
common
.
Hash
{})
{
return
nil
,
errors
.
New
(
"missing or corrupted snapshot"
)
}
cache
,
_
:=
bigcache
.
NewBigCache
(
bigcache
.
Config
{
// TODO(karalabe): dedup
...
...
@@ -391,16 +412,14 @@ func loadSnapshot(db ethdb.KeyValueStore, journal string, headNumber uint64, hea
journal
:
journal
,
db
:
db
,
cache
:
cache
,
number
:
number
,
root
:
root
,
root
:
baseRoot
,
}
// Load all the snapshot diffs from the journal, failing if their chain is broken
// or does not lead from the disk snapshot to the specified head.
if
_
,
err
:=
os
.
Stat
(
journal
);
os
.
IsNotExist
(
err
)
{
// Journal doesn't exist, don't worry if it's not supposed to
if
number
!=
headNumber
||
root
!=
headRoot
{
return
nil
,
fmt
.
Errorf
(
"snapshot journal missing, head doesn't match snapshot: #%d [%#x] vs. #%d [%#x]"
,
headNumber
,
headRoot
,
number
,
root
)
if
baseRoot
!=
root
{
return
nil
,
fmt
.
Errorf
(
"snapshot journal missing, head doesn't match snapshot: have %#x, want %#x"
,
baseRoot
,
root
)
}
return
base
,
nil
}
...
...
@@ -414,10 +433,8 @@ func loadSnapshot(db ethdb.KeyValueStore, journal string, headNumber uint64, hea
}
// Entire snapshot journal loaded, sanity check the head and return
// Journal doesn't exist, don't worry if it's not supposed to
number
,
root
=
snapshot
.
Info
()
if
number
!=
headNumber
||
root
!=
headRoot
{
return
nil
,
fmt
.
Errorf
(
"head doesn't match snapshot: #%d [%#x] vs. #%d [%#x]"
,
headNumber
,
headRoot
,
number
,
root
)
if
head
:=
snapshot
.
Root
();
head
!=
root
{
return
nil
,
fmt
.
Errorf
(
"head doesn't match snapshot: have %#x, want %#x"
,
head
,
root
)
}
return
snapshot
,
nil
}
core/state/snapshot/snapshot_test.go
View file @
d754091a
...
...
@@ -37,7 +37,7 @@ func TestDiskLayerExternalInvalidationFullFlatten(t *testing.T) {
root
:
common
.
HexToHash
(
"0x01"
),
cache
:
cache
,
}
snaps
:=
&
Snapshot
Tree
{
snaps
:=
&
Tree
{
layers
:
map
[
common
.
Hash
]
snapshot
{
base
.
root
:
base
,
},
...
...
@@ -83,7 +83,7 @@ func TestDiskLayerExternalInvalidationPartialFlatten(t *testing.T) {
root
:
common
.
HexToHash
(
"0x01"
),
cache
:
cache
,
}
snaps
:=
&
Snapshot
Tree
{
snaps
:=
&
Tree
{
layers
:
map
[
common
.
Hash
]
snapshot
{
base
.
root
:
base
,
},
...
...
@@ -132,7 +132,7 @@ func TestDiffLayerExternalInvalidationFullFlatten(t *testing.T) {
root
:
common
.
HexToHash
(
"0x01"
),
cache
:
cache
,
}
snaps
:=
&
Snapshot
Tree
{
snaps
:=
&
Tree
{
layers
:
map
[
common
.
Hash
]
snapshot
{
base
.
root
:
base
,
},
...
...
@@ -181,7 +181,7 @@ func TestDiffLayerExternalInvalidationPartialFlatten(t *testing.T) {
root
:
common
.
HexToHash
(
"0x01"
),
cache
:
cache
,
}
snaps
:=
&
Snapshot
Tree
{
snaps
:=
&
Tree
{
layers
:
map
[
common
.
Hash
]
snapshot
{
base
.
root
:
base
,
},
...
...
@@ -213,7 +213,6 @@ func TestDiffLayerExternalInvalidationPartialFlatten(t *testing.T) {
if
got
:=
len
(
snaps
.
layers
);
got
!=
exp
{
t
.
Errorf
(
"layers modified, got %d exp %d"
,
got
,
exp
)
}
// Flatten the diff layer into the bottom accumulator
if
err
:=
snaps
.
Cap
(
common
.
HexToHash
(
"0x04"
),
2
,
1024
*
1024
);
err
!=
nil
{
t
.
Fatalf
(
"failed to flatten diff layer into accumulator: %v"
,
err
)
...
...
@@ -247,7 +246,7 @@ func TestPostCapBasicDataAccess(t *testing.T) {
root
:
common
.
HexToHash
(
"0x01"
),
cache
:
cache
,
}
snaps
:=
&
Snapshot
Tree
{
snaps
:=
&
Tree
{
layers
:
map
[
common
.
Hash
]
snapshot
{
base
.
root
:
base
,
},
...
...
core/state/statedb.go
View file @
d754091a
...
...
@@ -68,7 +68,7 @@ type StateDB struct {
db
Database
trie
Trie
snaps
*
snapshot
.
Snapshot
Tree
snaps
*
snapshot
.
Tree
snap
snapshot
.
Snapshot
snapAccounts
map
[
common
.
Hash
][]
byte
snapStorage
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
...
...
@@ -117,7 +117,7 @@ type StateDB struct {
}
// Create a new state from a given trie.
func
New
(
root
common
.
Hash
,
db
Database
,
snaps
*
snapshot
.
Snapshot
Tree
)
(
*
StateDB
,
error
)
{
func
New
(
root
common
.
Hash
,
db
Database
,
snaps
*
snapshot
.
Tree
)
(
*
StateDB
,
error
)
{
tr
,
err
:=
db
.
OpenTrie
(
root
)
if
err
!=
nil
{
return
nil
,
err
...
...
@@ -840,13 +840,15 @@ func (s *StateDB) Commit(deleteEmptyObjects bool) (common.Hash, error) {
if
metrics
.
EnabledExpensive
{
defer
func
(
start
time
.
Time
)
{
s
.
SnapshotCommits
+=
time
.
Since
(
start
)
}(
time
.
Now
())
}
_
,
parentRoot
:=
s
.
snap
.
Info
()
if
err
:=
s
.
snaps
.
Update
(
root
,
parentRoot
,
s
.
snapAccounts
,
s
.
snapStorage
);
err
!=
nil
{
log
.
Warn
(
"Failed to update snapshot tree"
,
"from"
,
parentRoot
,
"to"
,
root
,
"err"
,
err
)
// Only update if there's a state transition (skip empty Clique blocks)
if
parent
:=
s
.
snap
.
Root
();
parent
!=
root
{
if
err
:=
s
.
snaps
.
Update
(
root
,
parent
,
s
.
snapAccounts
,
s
.
snapStorage
);
err
!=
nil
{
log
.
Warn
(
"Failed to update snapshot tree"
,
"from"
,
parent
,
"to"
,
root
,
"err"
,
err
)
}
if
err
:=
s
.
snaps
.
Cap
(
root
,
16
,
4
*
1024
*
1024
);
err
!=
nil
{
log
.
Warn
(
"Failed to cap snapshot tree"
,
"root"
,
root
,
"layers"
,
16
,
"memory"
,
4
*
1024
*
1024
,
"err"
,
err
)
}
}
s
.
snap
,
s
.
snapAccounts
,
s
.
snapStorage
=
nil
,
nil
,
nil
}
return
root
,
err
...
...
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