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
17637ed1
Unverified
Commit
17637ed1
authored
Dec 13, 2016
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
miner: clean up unconfirmed mined block tracking
parent
f15828e9
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
130 additions
and
74 deletions
+130
-74
pending.go
miner/pending.go
+116
-0
worker.go
miner/worker.go
+14
-74
No files found.
miner/pending.go
0 → 100644
View file @
17637ed1
// Copyright 2016 The go-ethereum Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum library is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// The go-ethereum library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
package
miner
import
(
"container/ring"
"sync"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
)
// pendingBlock is a small collection of metadata about a locally mined block
// that is placed into a pending set for canonical chain inclusion tracking.
type
pendingBlock
struct
{
index
uint64
hash
common
.
Hash
}
// pendingBlockSet implements a data structure to maintain locally mined blocks
// have have not yet reached enough maturity to guarantee chain inclusion. It is
// used by the miner to provide logs to the user when a previously mined block
// has a high enough guarantee to not be reorged out of te canonical chain.
type
pendingBlockSet
struct
{
chain
*
core
.
BlockChain
// Blockchain to verify canonical status through
depth
uint
// Depth after which to discard previous blocks
blocks
*
ring
.
Ring
// Block infos to allow canonical chain cross checks
lock
sync
.
RWMutex
// Protects the fields from concurrent access
}
// newPendingBlockSet returns new data structure to track currently pending blocks.
func
newPendingBlockSet
(
chain
*
core
.
BlockChain
,
depth
uint
)
*
pendingBlockSet
{
return
&
pendingBlockSet
{
chain
:
chain
,
depth
:
depth
,
}
}
// Insert adds a new block to the set of pending ones.
func
(
set
*
pendingBlockSet
)
Insert
(
index
uint64
,
hash
common
.
Hash
)
{
// If a new block was mined locally, shift out any old enough blocks
set
.
Shift
(
index
)
// Create the new item as its own ring
item
:=
ring
.
New
(
1
)
item
.
Value
=
&
pendingBlock
{
index
:
index
,
hash
:
hash
,
}
// Set as the initial ring or append to the end
set
.
lock
.
Lock
()
defer
set
.
lock
.
Unlock
()
if
set
.
blocks
==
nil
{
set
.
blocks
=
item
}
else
{
set
.
blocks
.
Move
(
-
1
)
.
Link
(
item
)
}
// Display a log for the user to notify of a new mined block pending
glog
.
V
(
logger
.
Info
)
.
Infof
(
"🔨 mined potential block #%d [%x…], waiting for %d blocks to confirm"
,
index
,
hash
.
Bytes
()[
:
4
],
set
.
depth
)
}
// Shift drops all pending blocks from the set which exceed the pending sets depth
// allowance, checking them against the canonical chain for inclusion or staleness
// report.
func
(
set
*
pendingBlockSet
)
Shift
(
height
uint64
)
{
set
.
lock
.
Lock
()
defer
set
.
lock
.
Unlock
()
// Short circuit if there are no pending blocks to shift
if
set
.
blocks
==
nil
{
return
}
// Otherwise shift all blocks below the depth allowance
for
set
.
blocks
!=
nil
{
// Retrieve the next pending block and abort if too fresh
next
:=
set
.
blocks
.
Value
.
(
*
pendingBlock
)
if
next
.
index
+
uint64
(
set
.
depth
)
>
height
{
break
}
// Block seems to exceed depth allowance, check for canonical status
header
:=
set
.
chain
.
GetHeaderByNumber
(
next
.
index
)
switch
{
case
header
==
nil
:
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"failed to retrieve header of mined block #%d [%x…]"
,
next
.
index
,
next
.
hash
.
Bytes
()[
:
4
])
case
header
.
Hash
()
==
next
.
hash
:
glog
.
V
(
logger
.
Info
)
.
Infof
(
"🔗 mined block #%d [%x…] reached canonical chain"
,
next
.
index
,
next
.
hash
.
Bytes
()[
:
4
])
default
:
glog
.
V
(
logger
.
Info
)
.
Infof
(
"⑂ mined block #%d [%x…] became a side fork"
,
next
.
index
,
next
.
hash
.
Bytes
()[
:
4
])
}
// Drop the block out of the ring
if
set
.
blocks
.
Value
==
set
.
blocks
.
Next
()
.
Value
{
set
.
blocks
=
nil
}
else
{
set
.
blocks
=
set
.
blocks
.
Move
(
-
1
)
set
.
blocks
.
Unlink
(
1
)
set
.
blocks
=
set
.
blocks
.
Move
(
1
)
}
}
}
miner/worker.go
View file @
17637ed1
...
...
@@ -55,26 +55,20 @@ type Agent interface {
GetHashRate
()
int64
}
type
uint64RingBuffer
struct
{
ints
[]
uint64
//array of all integers in buffer
next
int
//where is the next insertion? assert 0 <= next < len(ints)
}
// Work is the workers current environment and holds
// all of the current state information
type
Work
struct
{
config
*
params
.
ChainConfig
signer
types
.
Signer
state
*
state
.
StateDB
// apply state changes here
ancestors
*
set
.
Set
// ancestor set (used for checking uncle parent validity)
family
*
set
.
Set
// family set (used for checking uncle invalidity)
uncles
*
set
.
Set
// uncle set
tcount
int
// tx count in cycle
ownedAccounts
*
set
.
Set
lowGasTxs
types
.
Transactions
failedTxs
types
.
Transactions
localMinedBlocks
*
uint64RingBuffer
// the most recent block numbers that were mined locally (used to check block inclusion)
state
*
state
.
StateDB
// apply state changes here
ancestors
*
set
.
Set
// ancestor set (used for checking uncle parent validity)
family
*
set
.
Set
// family set (used for checking uncle invalidity)
uncles
*
set
.
Set
// uncle set
tcount
int
// tx count in cycle
ownedAccounts
*
set
.
Set
lowGasTxs
types
.
Transactions
failedTxs
types
.
Transactions
Block
*
types
.
Block
// the new block
...
...
@@ -123,6 +117,8 @@ type worker struct {
txQueueMu
sync
.
Mutex
txQueue
map
[
common
.
Hash
]
*
types
.
Transaction
minedBlocks
*
pendingBlockSet
// set of locally mined blocks pending canonicalness confirmations
// atomic status counters
mining
int32
atWork
int32
...
...
@@ -144,6 +140,7 @@ func newWorker(config *params.ChainConfig, coinbase common.Address, eth Backend,
coinbase
:
coinbase
,
txQueue
:
make
(
map
[
common
.
Hash
]
*
types
.
Transaction
),
agents
:
make
(
map
[
Agent
]
struct
{}),
minedBlocks
:
newPendingBlockSet
(
eth
.
BlockChain
(),
5
),
fullValidation
:
false
,
}
worker
.
events
=
worker
.
mux
.
Subscribe
(
core
.
ChainHeadEvent
{},
core
.
ChainSideEvent
{},
core
.
TxPreEvent
{})
...
...
@@ -269,18 +266,6 @@ func (self *worker) update() {
}
}
func
newLocalMinedBlock
(
blockNumber
uint64
,
prevMinedBlocks
*
uint64RingBuffer
)
(
minedBlocks
*
uint64RingBuffer
)
{
if
prevMinedBlocks
==
nil
{
minedBlocks
=
&
uint64RingBuffer
{
next
:
0
,
ints
:
make
([]
uint64
,
miningLogAtDepth
+
1
)}
}
else
{
minedBlocks
=
prevMinedBlocks
}
minedBlocks
.
ints
[
minedBlocks
.
next
]
=
blockNumber
minedBlocks
.
next
=
(
minedBlocks
.
next
+
1
)
%
len
(
minedBlocks
.
ints
)
return
minedBlocks
}
func
(
self
*
worker
)
wait
()
{
for
{
mustCommitNewWork
:=
true
...
...
@@ -355,17 +340,8 @@ func (self *worker) wait() {
}
}(
block
,
work
.
state
.
Logs
(),
work
.
receipts
)
}
// check staleness and display confirmation
var
stale
,
confirm
string
canonBlock
:=
self
.
chain
.
GetBlockByNumber
(
block
.
NumberU64
())
if
canonBlock
!=
nil
&&
canonBlock
.
Hash
()
!=
block
.
Hash
()
{
stale
=
"stale "
}
else
{
confirm
=
"Wait 5 blocks for confirmation"
work
.
localMinedBlocks
=
newLocalMinedBlock
(
block
.
Number
()
.
Uint64
(),
work
.
localMinedBlocks
)
}
glog
.
V
(
logger
.
Info
)
.
Infof
(
"🔨 Mined %sblock (#%v / %x). %s"
,
stale
,
block
.
Number
(),
block
.
Hash
()
.
Bytes
()[
:
4
],
confirm
)
// Insert the block into the set of pending ones to wait for confirmations
self
.
minedBlocks
.
Insert
(
block
.
NumberU64
(),
block
.
Hash
())
if
mustCommitNewWork
{
self
.
commitNewWork
()
...
...
@@ -417,9 +393,6 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error
// Keep track of transactions which return errors so they can be removed
work
.
tcount
=
0
work
.
ownedAccounts
=
accountAddressesSet
(
accounts
)
if
self
.
current
!=
nil
{
work
.
localMinedBlocks
=
self
.
current
.
localMinedBlocks
}
self
.
current
=
work
return
nil
}
...
...
@@ -435,38 +408,6 @@ func (w *worker) setGasPrice(p *big.Int) {
w
.
mux
.
Post
(
core
.
GasPriceChanged
{
Price
:
w
.
gasPrice
})
}
func
(
self
*
worker
)
isBlockLocallyMined
(
current
*
Work
,
deepBlockNum
uint64
)
bool
{
//Did this instance mine a block at {deepBlockNum} ?
var
isLocal
=
false
for
idx
,
blockNum
:=
range
current
.
localMinedBlocks
.
ints
{
if
deepBlockNum
==
blockNum
{
isLocal
=
true
current
.
localMinedBlocks
.
ints
[
idx
]
=
0
//prevent showing duplicate logs
break
}
}
//Short-circuit on false, because the previous and following tests must both be true
if
!
isLocal
{
return
false
}
//Does the block at {deepBlockNum} send earnings to my coinbase?
var
block
=
self
.
chain
.
GetBlockByNumber
(
deepBlockNum
)
return
block
!=
nil
&&
block
.
Coinbase
()
==
self
.
coinbase
}
func
(
self
*
worker
)
logLocalMinedBlocks
(
current
,
previous
*
Work
)
{
if
previous
!=
nil
&&
current
.
localMinedBlocks
!=
nil
{
nextBlockNum
:=
current
.
Block
.
NumberU64
()
for
checkBlockNum
:=
previous
.
Block
.
NumberU64
();
checkBlockNum
<
nextBlockNum
;
checkBlockNum
++
{
inspectBlockNum
:=
checkBlockNum
-
miningLogAtDepth
if
self
.
isBlockLocallyMined
(
current
,
inspectBlockNum
)
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"🔨 🔗 Mined %d blocks back: block #%v"
,
miningLogAtDepth
,
inspectBlockNum
)
}
}
}
}
func
(
self
*
worker
)
commitNewWork
()
{
self
.
mu
.
Lock
()
defer
self
.
mu
.
Unlock
()
...
...
@@ -513,7 +454,6 @@ func (self *worker) commitNewWork() {
}
}
}
previous
:=
self
.
current
// Could potentially happen if starting to mine in an odd state.
err
:=
self
.
makeCurrent
(
parent
,
header
)
if
err
!=
nil
{
...
...
@@ -574,7 +514,7 @@ func (self *worker) commitNewWork() {
// We only care about logging if we're actually mining.
if
atomic
.
LoadInt32
(
&
self
.
mining
)
==
1
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"commit new work on block %v with %d txs & %d uncles. Took %v
\n
"
,
work
.
Block
.
Number
(),
work
.
tcount
,
len
(
uncles
),
time
.
Since
(
tstart
))
self
.
logLocalMinedBlocks
(
work
,
previous
)
self
.
minedBlocks
.
Shift
(
work
.
Block
.
NumberU64
()
-
1
)
}
self
.
push
(
work
)
}
...
...
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