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
42f9f1f0
Unverified
Commit
42f9f1f0
authored
Jan 08, 2021
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
core/state: convert prefetcher to concurrent per-trie loader
parent
1e1865b7
Changes
9
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
384 additions
and
281 deletions
+384
-281
simulated.go
accounts/abi/bind/backends/simulated.go
+1
-2
blockchain.go
core/blockchain.go
+10
-20
state_object.go
core/state/state_object.go
+15
-7
state_test.go
core/state/state_test.go
+1
-1
statedb.go
core/state/statedb.go
+68
-59
statedb_test.go
core/state/statedb_test.go
+3
-3
trie_prefetcher.go
core/state/trie_prefetcher.go
+269
-184
api_tracer.go
eth/api_tracer.go
+4
-2
worker.go
miner/worker.go
+13
-3
No files found.
accounts/abi/bind/backends/simulated.go
View file @
42f9f1f0
...
...
@@ -125,10 +125,9 @@ func (b *SimulatedBackend) Rollback() {
func
(
b
*
SimulatedBackend
)
rollback
()
{
blocks
,
_
:=
core
.
GenerateChain
(
b
.
config
,
b
.
blockchain
.
CurrentBlock
(),
ethash
.
NewFaker
(),
b
.
database
,
1
,
func
(
int
,
*
core
.
BlockGen
)
{})
stateDB
,
_
:=
b
.
blockchain
.
State
()
b
.
pendingBlock
=
blocks
[
0
]
b
.
pendingState
,
_
=
state
.
New
(
b
.
pendingBlock
.
Root
(),
stateDB
.
Databas
e
(),
nil
)
b
.
pendingState
,
_
=
state
.
New
(
b
.
pendingBlock
.
Root
(),
b
.
blockchain
.
StateCach
e
(),
nil
)
}
// stateByBlockNumber retrieves a state by a given blocknumber.
...
...
core/blockchain.go
View file @
42f9f1f0
...
...
@@ -201,12 +201,11 @@ type BlockChain struct {
running
int32
// 0 if chain is running, 1 when stopped
procInterrupt
int32
// interrupt signaler for block processing
engine
consensus
.
Engine
validator
Validator
// Block and state validator interface
triePrefetcher
*
state
.
TriePrefetcher
// Trie prefetcher interface
prefetcher
Prefetcher
processor
Processor
// Block transaction processor interface
vmConfig
vm
.
Config
engine
consensus
.
Engine
validator
Validator
// Block and state validator interface
prefetcher
Prefetcher
processor
Processor
// Block transaction processor interface
vmConfig
vm
.
Config
shouldPreserve
func
(
*
types
.
Block
)
bool
// Function used to determine whether should preserve the given block.
terminateInsert
func
(
common
.
Hash
,
uint64
)
bool
// Testing hook used to terminate ancient receipt chain insertion.
...
...
@@ -250,15 +249,6 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
}
bc
.
validator
=
NewBlockValidator
(
chainConfig
,
bc
,
engine
)
bc
.
prefetcher
=
newStatePrefetcher
(
chainConfig
,
bc
,
engine
)
tp
:=
state
.
NewTriePrefetcher
(
bc
.
stateCache
)
bc
.
wg
.
Add
(
1
)
go
func
()
{
tp
.
Loop
()
bc
.
wg
.
Done
()
}()
bc
.
triePrefetcher
=
tp
bc
.
processor
=
NewStateProcessor
(
chainConfig
,
bc
,
engine
)
var
err
error
...
...
@@ -1001,9 +991,6 @@ func (bc *BlockChain) Stop() {
bc
.
scope
.
Close
()
close
(
bc
.
quit
)
bc
.
StopInsert
()
if
bc
.
triePrefetcher
!=
nil
{
bc
.
triePrefetcher
.
Close
()
}
bc
.
wg
.
Wait
()
// Ensure that the entirety of the state snapshot is journalled to disk.
...
...
@@ -1870,16 +1857,20 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
parent
=
bc
.
GetHeader
(
block
.
ParentHash
(),
block
.
NumberU64
()
-
1
)
}
statedb
,
err
:=
state
.
New
(
parent
.
Root
,
bc
.
stateCache
,
bc
.
snaps
)
statedb
.
UsePrefetcher
(
bc
.
triePrefetcher
)
if
err
!=
nil
{
return
it
.
index
,
err
}
// Enable prefetching to pull in trie node paths while processing transactions
statedb
.
StartPrefetcher
(
"chain"
)
defer
statedb
.
StopPrefetcher
()
// stopped on write anyway, defer meant to catch early error returns
// If we have a followup block, run that against the current state to pre-cache
// transactions and probabilistically some of the account/storage trie nodes.
var
followupInterrupt
uint32
if
!
bc
.
cacheConfig
.
TrieCleanNoPrefetch
{
if
followup
,
err
:=
it
.
peek
();
followup
!=
nil
&&
err
==
nil
{
throwaway
,
_
:=
state
.
New
(
parent
.
Root
,
bc
.
stateCache
,
bc
.
snaps
)
go
func
(
start
time
.
Time
,
followup
*
types
.
Block
,
throwaway
*
state
.
StateDB
,
interrupt
*
uint32
)
{
bc
.
prefetcher
.
Prefetch
(
followup
,
throwaway
,
bc
.
vmConfig
,
&
followupInterrupt
)
...
...
@@ -1933,7 +1924,6 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er
if
err
!=
nil
{
return
it
.
index
,
err
}
// Update the metrics touched during block commit
accountCommitTimer
.
Update
(
statedb
.
AccountCommits
)
// Account commits are complete, we can mark them
storageCommitTimer
.
Update
(
statedb
.
StorageCommits
)
// Storage commits are complete, we can mark them
...
...
core/state/state_object.go
View file @
42f9f1f0
...
...
@@ -162,7 +162,7 @@ func (s *stateObject) getTrie(db Database) Trie {
if
s
.
data
.
Root
!=
emptyRoot
&&
s
.
db
.
prefetcher
!=
nil
{
// When the miner is creating the pending state, there is no
// prefetcher
s
.
trie
=
s
.
db
.
prefetcher
.
GetT
rie
(
s
.
data
.
Root
)
s
.
trie
=
s
.
db
.
prefetcher
.
t
rie
(
s
.
data
.
Root
)
}
if
s
.
trie
==
nil
{
var
err
error
...
...
@@ -309,14 +309,16 @@ func (s *stateObject) setState(key, value common.Hash) {
// finalise moves all dirty storage slots into the pending area to be hashed or
// committed later. It is invoked at the end of every transaction.
func
(
s
*
stateObject
)
finalise
()
{
trieChanges
:=
make
([]
common
.
Hash
,
0
,
len
(
s
.
dirtyStorage
))
func
(
s
*
stateObject
)
finalise
(
prefetch
bool
)
{
slotsToPrefetch
:=
make
([][]
byte
,
0
,
len
(
s
.
dirtyStorage
))
for
key
,
value
:=
range
s
.
dirtyStorage
{
s
.
pendingStorage
[
key
]
=
value
trieChanges
=
append
(
trieChanges
,
key
)
if
value
!=
s
.
originStorage
[
key
]
{
slotsToPrefetch
=
append
(
slotsToPrefetch
,
common
.
CopyBytes
(
key
[
:
]))
// Copy needed for closure
}
}
if
len
(
trieChanges
)
>
0
&&
s
.
db
.
prefetcher
!=
nil
&&
s
.
data
.
Root
!=
emptyRoot
{
s
.
db
.
prefetcher
.
PrefetchStorage
(
s
.
data
.
Root
,
trieChanges
)
if
s
.
db
.
prefetcher
!=
nil
&&
prefetch
&&
len
(
slotsToPrefetch
)
>
0
&&
s
.
data
.
Root
!=
emptyRoot
{
s
.
db
.
prefetcher
.
prefetch
(
s
.
data
.
Root
,
slotsToPrefetch
)
}
if
len
(
s
.
dirtyStorage
)
>
0
{
s
.
dirtyStorage
=
make
(
Storage
)
...
...
@@ -327,7 +329,7 @@ func (s *stateObject) finalise() {
// It will return nil if the trie has not been loaded and no changes have been made
func
(
s
*
stateObject
)
updateTrie
(
db
Database
)
Trie
{
// Make sure all dirty slots are finalized into the pending storage area
s
.
finalise
(
)
s
.
finalise
(
false
)
// Don't prefetch any more, pull directly if need be
if
len
(
s
.
pendingStorage
)
==
0
{
return
s
.
trie
}
...
...
@@ -340,6 +342,8 @@ func (s *stateObject) updateTrie(db Database) Trie {
// Insert all the pending updates into the trie
tr
:=
s
.
getTrie
(
db
)
hasher
:=
s
.
db
.
hasher
usedStorage
:=
make
([][]
byte
,
0
,
len
(
s
.
pendingStorage
))
for
key
,
value
:=
range
s
.
pendingStorage
{
// Skip noop changes, persist actual changes
if
value
==
s
.
originStorage
[
key
]
{
...
...
@@ -366,6 +370,10 @@ func (s *stateObject) updateTrie(db Database) Trie {
}
storage
[
crypto
.
HashData
(
hasher
,
key
[
:
])]
=
v
// v will be nil if value is 0x00
}
usedStorage
=
append
(
usedStorage
,
common
.
CopyBytes
(
key
[
:
]))
// Copy needed for closure
}
if
s
.
db
.
prefetcher
!=
nil
{
s
.
db
.
prefetcher
.
used
(
s
.
data
.
Root
,
usedStorage
)
}
if
len
(
s
.
pendingStorage
)
>
0
{
s
.
pendingStorage
=
make
(
Storage
)
...
...
core/state/state_test.go
View file @
42f9f1f0
...
...
@@ -170,7 +170,7 @@ func TestSnapshot2(t *testing.T) {
state
.
setStateObject
(
so0
)
root
,
_
:=
state
.
Commit
(
false
)
state
.
Reset
(
root
)
state
,
_
=
New
(
root
,
state
.
db
,
state
.
snaps
)
// and one with deleted == true
so1
:=
state
.
getStateObject
(
stateobjaddr1
)
...
...
core/state/statedb.go
View file @
42f9f1f0
...
...
@@ -63,7 +63,7 @@ func (n *proofList) Delete(key []byte) error {
// * Accounts
type
StateDB
struct
{
db
Database
prefetcher
*
T
riePrefetcher
prefetcher
*
t
riePrefetcher
originalRoot
common
.
Hash
// The pre-state root, before any changes were made
trie
Trie
hasher
crypto
.
KeccakState
...
...
@@ -149,10 +149,25 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error)
return
sdb
,
nil
}
func
(
s
*
StateDB
)
UsePrefetcher
(
prefetcher
*
TriePrefetcher
)
{
if
prefetcher
!=
nil
{
s
.
prefetcher
=
prefetcher
s
.
prefetcher
.
Resume
(
s
.
originalRoot
)
// StartPrefetcher initializes a new trie prefetcher to pull in nodes from the
// state trie concurrently while the state is mutated so that when we reach the
// commit phase, most of the needed data is already hot.
func
(
s
*
StateDB
)
StartPrefetcher
(
namespace
string
)
{
if
s
.
prefetcher
!=
nil
{
s
.
prefetcher
.
close
()
s
.
prefetcher
=
nil
}
if
s
.
snap
!=
nil
{
s
.
prefetcher
=
newTriePrefetcher
(
s
.
db
,
s
.
originalRoot
,
namespace
)
}
}
// StopPrefetcher terminates a running prefetcher and reports any leftover stats
// from the gathered metrics.
func
(
s
*
StateDB
)
StopPrefetcher
()
{
if
s
.
prefetcher
!=
nil
{
s
.
prefetcher
.
close
()
s
.
prefetcher
=
nil
}
}
...
...
@@ -167,37 +182,6 @@ func (s *StateDB) Error() error {
return
s
.
dbErr
}
// Reset clears out all ephemeral state objects from the state db, but keeps
// the underlying state trie to avoid reloading data for the next operations.
func
(
s
*
StateDB
)
Reset
(
root
common
.
Hash
)
error
{
tr
,
err
:=
s
.
db
.
OpenTrie
(
root
)
if
err
!=
nil
{
return
err
}
s
.
trie
=
tr
s
.
stateObjects
=
make
(
map
[
common
.
Address
]
*
stateObject
)
s
.
stateObjectsPending
=
make
(
map
[
common
.
Address
]
struct
{})
s
.
stateObjectsDirty
=
make
(
map
[
common
.
Address
]
struct
{})
s
.
thash
=
common
.
Hash
{}
s
.
bhash
=
common
.
Hash
{}
s
.
txIndex
=
0
s
.
logs
=
make
(
map
[
common
.
Hash
][]
*
types
.
Log
)
s
.
logSize
=
0
s
.
preimages
=
make
(
map
[
common
.
Hash
][]
byte
)
s
.
clearJournalAndRefund
()
if
s
.
snaps
!=
nil
{
s
.
snapAccounts
,
s
.
snapDestructs
,
s
.
snapStorage
=
nil
,
nil
,
nil
if
s
.
snap
=
s
.
snaps
.
Snapshot
(
root
);
s
.
snap
!=
nil
{
s
.
snapDestructs
=
make
(
map
[
common
.
Hash
]
struct
{})
s
.
snapAccounts
=
make
(
map
[
common
.
Hash
][]
byte
)
s
.
snapStorage
=
make
(
map
[
common
.
Hash
]
map
[
common
.
Hash
][]
byte
)
}
}
s
.
accessList
=
newAccessList
()
return
nil
}
func
(
s
*
StateDB
)
AddLog
(
log
*
types
.
Log
)
{
s
.
journal
.
append
(
addLogChange
{
txhash
:
s
.
thash
})
...
...
@@ -737,6 +721,13 @@ func (s *StateDB) Copy() *StateDB {
// However, it doesn't cost us much to copy an empty list, so we do it anyway
// to not blow up if we ever decide copy it in the middle of a transaction
state
.
accessList
=
s
.
accessList
.
Copy
()
// If there's a prefetcher running, make an inactive copy of it that can
// only access data but does not actively preload (since the user will not
// know that they need to explicitly terminate an active copy).
if
s
.
prefetcher
!=
nil
{
state
.
prefetcher
=
s
.
prefetcher
.
copy
()
}
return
state
}
...
...
@@ -773,7 +764,7 @@ func (s *StateDB) GetRefund() uint64 {
// the journal as well as the refunds. Finalise, however, will not push any updates
// into the tries just yet. Only IntermediateRoot or Commit will do that.
func
(
s
*
StateDB
)
Finalise
(
deleteEmptyObjects
bool
)
{
var
addressesToPrefetch
[]
common
.
Address
addressesToPrefetch
:=
make
([][]
byte
,
0
,
len
(
s
.
journal
.
dirties
))
for
addr
:=
range
s
.
journal
.
dirties
{
obj
,
exist
:=
s
.
stateObjects
[
addr
]
if
!
exist
{
...
...
@@ -798,21 +789,19 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
delete
(
s
.
snapStorage
,
obj
.
addrHash
)
// Clear out any previously updated storage data (may be recreated via a ressurrect)
}
}
else
{
obj
.
finalise
(
)
obj
.
finalise
(
true
)
// Prefetch slots in the background
}
s
.
stateObjectsPending
[
addr
]
=
struct
{}{}
s
.
stateObjectsDirty
[
addr
]
=
struct
{}{}
// At this point, also ship the address off to the precacher. The precacher
// will start loading tries, and when the change is eventually committed,
// the commit-phase will be a lot faster
if
s
.
prefetcher
!=
nil
{
addressesToPrefetch
=
append
(
addressesToPrefetch
,
addr
)
}
addressesToPrefetch
=
append
(
addressesToPrefetch
,
common
.
CopyBytes
(
addr
[
:
]))
// Copy needed for closure
}
if
s
.
prefetcher
!=
nil
{
s
.
prefetcher
.
PrefetchAddresses
(
addressesToPrefetch
)
if
s
.
prefetcher
!=
nil
&&
len
(
addressesToPrefetch
)
>
0
{
s
.
prefetcher
.
prefetch
(
s
.
originalRoot
,
addressesToPrefetch
)
}
// Invalidate journal because reverting across transactions is not allowed.
s
.
clearJournalAndRefund
()
}
...
...
@@ -824,29 +813,49 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
// Finalise all the dirty storage states and write them into the tries
s
.
Finalise
(
deleteEmptyObjects
)
// Now we're about to start to write changes to the trie. The trie is so
// far _untouched_. We can check with the prefetcher, if it can give us
// a trie which has the same root, but also has some content loaded into it.
// If so, use that one instead.
// If there was a trie prefetcher operating, it gets aborted and irrevocably
// modified after we start retrieving tries. Remove it from the statedb after
// this round of use.
//
// This is weird pre-byzantium since the first tx runs with a prefetcher and
// the remainder without, but pre-byzantium even the initial prefetcher is
// useless, so no sleep lost.
prefetcher
:=
s
.
prefetcher
if
s
.
prefetcher
!=
nil
{
s
.
prefetcher
.
Pause
()
// We only want to do this _once_, if someone calls IntermediateRoot again,
// we shouldn't fetch the trie again
if
s
.
originalRoot
!=
(
common
.
Hash
{})
{
if
trie
:=
s
.
prefetcher
.
GetTrie
(
s
.
originalRoot
);
trie
!=
nil
{
s
.
trie
=
trie
}
s
.
originalRoot
=
common
.
Hash
{}
defer
func
()
{
s
.
prefetcher
.
close
()
s
.
prefetcher
=
nil
}()
}
// Although naively it makes sense to retrieve the account trie and then do
// the contract storage and account updates sequentially, that short circuits
// the account prefetcher. Instead, let's process all the storage updates
// first, giving the account prefeches just a few more milliseconds of time
// to pull useful data from disk.
for
addr
:=
range
s
.
stateObjectsPending
{
if
obj
:=
s
.
stateObjects
[
addr
];
!
obj
.
deleted
{
obj
.
updateRoot
(
s
.
db
)
}
}
// Now we're about to start to write changes to the trie. The trie is so far
// _untouched_. We can check with the prefetcher, if it can give us a trie
// which has the same root, but also has some content loaded into it.
if
prefetcher
!=
nil
{
if
trie
:=
prefetcher
.
trie
(
s
.
originalRoot
);
trie
!=
nil
{
s
.
trie
=
trie
}
}
usedAddrs
:=
make
([][]
byte
,
0
,
len
(
s
.
stateObjectsPending
))
for
addr
:=
range
s
.
stateObjectsPending
{
obj
:=
s
.
stateObjects
[
addr
]
if
obj
.
deleted
{
if
obj
:=
s
.
stateObjects
[
addr
];
obj
.
deleted
{
s
.
deleteStateObject
(
obj
)
}
else
{
obj
.
updateRoot
(
s
.
db
)
s
.
updateStateObject
(
obj
)
}
usedAddrs
=
append
(
usedAddrs
,
common
.
CopyBytes
(
addr
[
:
]))
// Copy needed for closure
}
if
prefetcher
!=
nil
{
prefetcher
.
used
(
s
.
originalRoot
,
usedAddrs
)
}
if
len
(
s
.
stateObjectsPending
)
>
0
{
s
.
stateObjectsPending
=
make
(
map
[
common
.
Address
]
struct
{})
...
...
core/state/statedb_test.go
View file @
42f9f1f0
...
...
@@ -474,7 +474,7 @@ func TestTouchDelete(t *testing.T) {
s
:=
newStateTest
()
s
.
state
.
GetOrNewStateObject
(
common
.
Address
{})
root
,
_
:=
s
.
state
.
Commit
(
false
)
s
.
state
.
Reset
(
root
)
s
.
state
,
_
=
New
(
root
,
s
.
state
.
db
,
s
.
state
.
snaps
)
snapshot
:=
s
.
state
.
Snapshot
()
s
.
state
.
AddBalance
(
common
.
Address
{},
new
(
big
.
Int
))
...
...
@@ -676,7 +676,7 @@ func TestDeleteCreateRevert(t *testing.T) {
state
.
SetBalance
(
addr
,
big
.
NewInt
(
1
))
root
,
_
:=
state
.
Commit
(
false
)
state
.
Reset
(
root
)
state
,
_
=
New
(
root
,
state
.
db
,
state
.
snaps
)
// Simulate self-destructing in one transaction, then create-reverting in another
state
.
Suicide
(
addr
)
...
...
@@ -688,7 +688,7 @@ func TestDeleteCreateRevert(t *testing.T) {
// Commit the entire state and make sure we don't crash and have the correct state
root
,
_
=
state
.
Commit
(
true
)
state
.
Reset
(
root
)
state
,
_
=
New
(
root
,
state
.
db
,
state
.
snaps
)
if
state
.
getStateObject
(
addr
)
!=
nil
{
t
.
Fatalf
(
"self-destructed contract came alive"
)
...
...
core/state/trie_prefetcher.go
View file @
42f9f1f0
This diff is collapsed.
Click to expand it.
eth/api_tracer.go
View file @
42f9f1f0
...
...
@@ -299,7 +299,8 @@ func (api *PrivateDebugAPI) traceChain(ctx context.Context, start, end *types.Bl
failed
=
err
break
}
if
err
:=
statedb
.
Reset
(
root
);
err
!=
nil
{
statedb
,
err
=
state
.
New
(
root
,
database
,
nil
)
if
err
!=
nil
{
failed
=
err
break
}
...
...
@@ -699,7 +700,8 @@ func (api *PrivateDebugAPI) computeStateDB(block *types.Block, reexec uint64) (*
if
err
!=
nil
{
return
nil
,
err
}
if
err
:=
statedb
.
Reset
(
root
);
err
!=
nil
{
statedb
,
err
=
state
.
New
(
root
,
database
,
nil
)
if
err
!=
nil
{
return
nil
,
fmt
.
Errorf
(
"state reset after block %d failed: %v"
,
block
.
NumberU64
(),
err
)
}
database
.
TrieDB
()
.
Reference
(
root
,
common
.
Hash
{})
...
...
miner/worker.go
View file @
42f9f1f0
...
...
@@ -303,6 +303,9 @@ func (w *worker) isRunning() bool {
// close terminates all background threads maintained by the worker.
// Note the worker does not support being closed multiple times.
func
(
w
*
worker
)
close
()
{
if
w
.
current
!=
nil
&&
w
.
current
.
state
!=
nil
{
w
.
current
.
state
.
StopPrefetcher
()
}
atomic
.
StoreInt32
(
&
w
.
running
,
0
)
close
(
w
.
exitCh
)
}
...
...
@@ -642,10 +645,14 @@ func (w *worker) resultLoop() {
// makeCurrent creates a new environment for the current cycle.
func
(
w
*
worker
)
makeCurrent
(
parent
*
types
.
Block
,
header
*
types
.
Header
)
error
{
// Retrieve the parent state to execute on top and start a prefetcher for
// the miner to speed block sealing up a bit
state
,
err
:=
w
.
chain
.
StateAt
(
parent
.
Root
())
if
err
!=
nil
{
return
err
}
state
.
StartPrefetcher
(
"miner"
)
env
:=
&
environment
{
signer
:
types
.
NewEIP155Signer
(
w
.
chainConfig
.
ChainID
),
state
:
state
,
...
...
@@ -654,7 +661,6 @@ func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error {
uncles
:
mapset
.
NewSet
(),
header
:
header
,
}
// when 08 is processed ancestors contain 07 (quick block)
for
_
,
ancestor
:=
range
w
.
chain
.
GetBlocksFromHash
(
parent
.
Hash
(),
7
)
{
for
_
,
uncle
:=
range
ancestor
.
Uncles
()
{
...
...
@@ -663,9 +669,14 @@ func (w *worker) makeCurrent(parent *types.Block, header *types.Header) error {
env
.
family
.
Add
(
ancestor
.
Hash
())
env
.
ancestors
.
Add
(
ancestor
.
Hash
())
}
// Keep track of transactions which return errors so they can be removed
env
.
tcount
=
0
// Swap out the old work with the new one, terminating any leftover prefetcher
// processes in the mean time and starting a new one.
if
w
.
current
!=
nil
&&
w
.
current
.
state
!=
nil
{
w
.
current
.
state
.
StopPrefetcher
()
}
w
.
current
=
env
return
nil
}
...
...
@@ -719,7 +730,6 @@ func (w *worker) updateSnapshot() {
w
.
current
.
receipts
,
new
(
trie
.
Trie
),
)
w
.
snapshotState
=
w
.
current
.
state
.
Copy
()
}
...
...
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