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
39ce85cf
Commit
39ce85cf
authored
May 13, 2016
by
Péter Szilágyi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
eth/downloader: bound fork ancestry and allow heavy short forks
parent
72e60dea
Changes
2
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
201 additions
and
43 deletions
+201
-43
downloader.go
eth/downloader/downloader.go
+57
-11
downloader_test.go
eth/downloader/downloader_test.go
+144
-32
No files found.
eth/downloader/downloader.go
View file @
39ce85cf
...
@@ -34,6 +34,7 @@ import (
...
@@ -34,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
"github.com/rcrowley/go-metrics"
"github.com/rcrowley/go-metrics"
)
)
...
@@ -45,6 +46,8 @@ var (
...
@@ -45,6 +46,8 @@ var (
MaxReceiptFetch
=
256
// Amount of transaction receipts to allow fetching per request
MaxReceiptFetch
=
256
// Amount of transaction receipts to allow fetching per request
MaxStateFetch
=
384
// Amount of node state values to allow fetching per request
MaxStateFetch
=
384
// Amount of node state values to allow fetching per request
MaxForkAncestry
=
3
*
params
.
EpochDuration
.
Uint64
()
// Maximum chain reorganisation
hashTTL
=
3
*
time
.
Second
// [eth/61] Time it takes for a hash request to time out
hashTTL
=
3
*
time
.
Second
// [eth/61] Time it takes for a hash request to time out
blockTargetRTT
=
3
*
time
.
Second
/
2
// [eth/61] Target time for completing a block retrieval request
blockTargetRTT
=
3
*
time
.
Second
/
2
// [eth/61] Target time for completing a block retrieval request
blockTTL
=
3
*
blockTargetRTT
// [eth/61] Maximum time allowance before a block request is considered expired
blockTTL
=
3
*
blockTargetRTT
// [eth/61] Maximum time allowance before a block request is considered expired
...
@@ -79,6 +82,7 @@ var (
...
@@ -79,6 +82,7 @@ var (
errEmptyHeaderSet
=
errors
.
New
(
"empty header set by peer"
)
errEmptyHeaderSet
=
errors
.
New
(
"empty header set by peer"
)
errPeersUnavailable
=
errors
.
New
(
"no peers available or all tried for download"
)
errPeersUnavailable
=
errors
.
New
(
"no peers available or all tried for download"
)
errAlreadyInPool
=
errors
.
New
(
"hash already in pool"
)
errAlreadyInPool
=
errors
.
New
(
"hash already in pool"
)
errInvalidAncestor
=
errors
.
New
(
"retrieved ancestor is invalid"
)
errInvalidChain
=
errors
.
New
(
"retrieved hash chain is invalid"
)
errInvalidChain
=
errors
.
New
(
"retrieved hash chain is invalid"
)
errInvalidBlock
=
errors
.
New
(
"retrieved block is invalid"
)
errInvalidBlock
=
errors
.
New
(
"retrieved block is invalid"
)
errInvalidBody
=
errors
.
New
(
"retrieved block body is invalid"
)
errInvalidBody
=
errors
.
New
(
"retrieved block body is invalid"
)
...
@@ -266,7 +270,7 @@ func (d *Downloader) Synchronise(id string, head common.Hash, td *big.Int, mode
...
@@ -266,7 +270,7 @@ func (d *Downloader) Synchronise(id string, head common.Hash, td *big.Int, mode
case
errBusy
:
case
errBusy
:
glog
.
V
(
logger
.
Detail
)
.
Infof
(
"Synchronisation already in progress"
)
glog
.
V
(
logger
.
Detail
)
.
Infof
(
"Synchronisation already in progress"
)
case
errTimeout
,
errBadPeer
,
errStallingPeer
,
errEmptyHashSet
,
errEmptyHeaderSet
,
errPeersUnavailable
,
errInvalidChain
:
case
errTimeout
,
errBadPeer
,
errStallingPeer
,
errEmptyHashSet
,
errEmptyHeaderSet
,
errPeersUnavailable
,
errInvalid
Ancestor
,
errInvalid
Chain
:
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"Removing peer %v: %v"
,
id
,
err
)
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"Removing peer %v: %v"
,
id
,
err
)
d
.
dropPeer
(
id
)
d
.
dropPeer
(
id
)
...
@@ -353,7 +357,7 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash, td *big.Int) (err e
...
@@ -353,7 +357,7 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash, td *big.Int) (err e
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
origin
,
err
:=
d
.
findAncestor61
(
p
)
origin
,
err
:=
d
.
findAncestor61
(
p
,
latest
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -380,7 +384,7 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash, td *big.Int) (err e
...
@@ -380,7 +384,7 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash, td *big.Int) (err e
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
origin
,
err
:=
d
.
findAncestor
(
p
)
origin
,
err
:=
d
.
findAncestor
(
p
,
latest
)
if
err
!=
nil
{
if
err
!=
nil
{
return
err
return
err
}
}
...
@@ -536,11 +540,19 @@ func (d *Downloader) fetchHeight61(p *peer) (uint64, error) {
...
@@ -536,11 +540,19 @@ func (d *Downloader) fetchHeight61(p *peer) (uint64, error) {
// on the correct chain, checking the top N blocks should already get us a match.
// on the correct chain, checking the top N blocks should already get us a match.
// In the rare scenario when we ended up on a long reorganisation (i.e. none of
// In the rare scenario when we ended up on a long reorganisation (i.e. none of
// the head blocks match), we do a binary search to find the common ancestor.
// the head blocks match), we do a binary search to find the common ancestor.
func
(
d
*
Downloader
)
findAncestor61
(
p
*
peer
)
(
uint64
,
error
)
{
func
(
d
*
Downloader
)
findAncestor61
(
p
*
peer
,
height
uint64
)
(
uint64
,
error
)
{
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"%v: looking for common ancestor"
,
p
)
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"%v: looking for common ancestor"
,
p
)
// Request out head blocks to short circuit ancestor location
// Figure out the valid ancestor range to prevent rewrite attacks
head
:=
d
.
headBlock
()
.
NumberU64
()
floor
,
ceil
:=
int64
(
-
1
),
d
.
headBlock
()
.
NumberU64
()
if
ceil
>=
MaxForkAncestry
{
floor
=
int64
(
ceil
-
MaxForkAncestry
)
}
// Request the topmost blocks to short circuit binary ancestor lookup
head
:=
ceil
if
head
>
height
{
head
=
height
}
from
:=
int64
(
head
)
-
int64
(
MaxHashFetch
)
+
1
from
:=
int64
(
head
)
-
int64
(
MaxHashFetch
)
+
1
if
from
<
0
{
if
from
<
0
{
from
=
0
from
=
0
...
@@ -600,11 +612,18 @@ func (d *Downloader) findAncestor61(p *peer) (uint64, error) {
...
@@ -600,11 +612,18 @@ func (d *Downloader) findAncestor61(p *peer) (uint64, error) {
}
}
// If the head fetch already found an ancestor, return
// If the head fetch already found an ancestor, return
if
!
common
.
EmptyHash
(
hash
)
{
if
!
common
.
EmptyHash
(
hash
)
{
if
int64
(
number
)
<=
floor
{
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"%v: potential rewrite attack: #%d [%x…] <= #%d limit"
,
p
,
number
,
hash
[
:
4
],
floor
)
return
0
,
errInvalidAncestor
}
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"%v: common ancestor: #%d [%x…]"
,
p
,
number
,
hash
[
:
4
])
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"%v: common ancestor: #%d [%x…]"
,
p
,
number
,
hash
[
:
4
])
return
number
,
nil
return
number
,
nil
}
}
// Ancestor not found, we need to binary search over our chain
// Ancestor not found, we need to binary search over our chain
start
,
end
:=
uint64
(
0
),
head
start
,
end
:=
uint64
(
0
),
head
if
floor
>
0
{
start
=
uint64
(
floor
)
}
for
start
+
1
<
end
{
for
start
+
1
<
end
{
// Split our chain interval in two, and request the hash to cross check
// Split our chain interval in two, and request the hash to cross check
check
:=
(
start
+
end
)
/
2
check
:=
(
start
+
end
)
/
2
...
@@ -660,6 +679,12 @@ func (d *Downloader) findAncestor61(p *peer) (uint64, error) {
...
@@ -660,6 +679,12 @@ func (d *Downloader) findAncestor61(p *peer) (uint64, error) {
}
}
}
}
}
}
// Ensure valid ancestry and return
if
int64
(
start
)
<=
floor
{
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"%v: potential rewrite attack: #%d [%x…] <= #%d limit"
,
p
,
start
,
hash
[
:
4
],
floor
)
return
0
,
errInvalidAncestor
}
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"%v: common ancestor: #%d [%x…]"
,
p
,
start
,
hash
[
:
4
])
return
start
,
nil
return
start
,
nil
}
}
...
@@ -961,15 +986,23 @@ func (d *Downloader) fetchHeight(p *peer) (uint64, error) {
...
@@ -961,15 +986,23 @@ func (d *Downloader) fetchHeight(p *peer) (uint64, error) {
// on the correct chain, checking the top N links should already get us a match.
// on the correct chain, checking the top N links should already get us a match.
// In the rare scenario when we ended up on a long reorganisation (i.e. none of
// In the rare scenario when we ended up on a long reorganisation (i.e. none of
// the head links match), we do a binary search to find the common ancestor.
// the head links match), we do a binary search to find the common ancestor.
func
(
d
*
Downloader
)
findAncestor
(
p
*
peer
)
(
uint64
,
error
)
{
func
(
d
*
Downloader
)
findAncestor
(
p
*
peer
,
height
uint64
)
(
uint64
,
error
)
{
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"%v: looking for common ancestor"
,
p
)
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"%v: looking for common ancestor"
,
p
)
//
Request our head headers to short circuit ancestor location
//
Figure out the valid ancestor range to prevent rewrite attacks
head
:=
d
.
headHeader
()
.
Number
.
Uint64
()
floor
,
ceil
:=
int64
(
-
1
),
d
.
headHeader
()
.
Number
.
Uint64
()
if
d
.
mode
==
FullSync
{
if
d
.
mode
==
FullSync
{
head
=
d
.
headBlock
()
.
NumberU64
()
ceil
=
d
.
headBlock
()
.
NumberU64
()
}
else
if
d
.
mode
==
FastSync
{
}
else
if
d
.
mode
==
FastSync
{
head
=
d
.
headFastBlock
()
.
NumberU64
()
ceil
=
d
.
headFastBlock
()
.
NumberU64
()
}
if
ceil
>=
MaxForkAncestry
{
floor
=
int64
(
ceil
-
MaxForkAncestry
)
}
// Request the topmost blocks to short circuit binary ancestor lookup
head
:=
ceil
if
head
>
height
{
head
=
height
}
}
from
:=
int64
(
head
)
-
int64
(
MaxHeaderFetch
)
+
1
from
:=
int64
(
head
)
-
int64
(
MaxHeaderFetch
)
+
1
if
from
<
0
{
if
from
<
0
{
...
@@ -1040,11 +1073,18 @@ func (d *Downloader) findAncestor(p *peer) (uint64, error) {
...
@@ -1040,11 +1073,18 @@ func (d *Downloader) findAncestor(p *peer) (uint64, error) {
}
}
// If the head fetch already found an ancestor, return
// If the head fetch already found an ancestor, return
if
!
common
.
EmptyHash
(
hash
)
{
if
!
common
.
EmptyHash
(
hash
)
{
if
int64
(
number
)
<=
floor
{
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"%v: potential rewrite attack: #%d [%x…] <= #%d limit"
,
p
,
number
,
hash
[
:
4
],
floor
)
return
0
,
errInvalidAncestor
}
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"%v: common ancestor: #%d [%x…]"
,
p
,
number
,
hash
[
:
4
])
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"%v: common ancestor: #%d [%x…]"
,
p
,
number
,
hash
[
:
4
])
return
number
,
nil
return
number
,
nil
}
}
// Ancestor not found, we need to binary search over our chain
// Ancestor not found, we need to binary search over our chain
start
,
end
:=
uint64
(
0
),
head
start
,
end
:=
uint64
(
0
),
head
if
floor
>
0
{
start
=
uint64
(
floor
)
}
for
start
+
1
<
end
{
for
start
+
1
<
end
{
// Split our chain interval in two, and request the hash to cross check
// Split our chain interval in two, and request the hash to cross check
check
:=
(
start
+
end
)
/
2
check
:=
(
start
+
end
)
/
2
...
@@ -1100,6 +1140,12 @@ func (d *Downloader) findAncestor(p *peer) (uint64, error) {
...
@@ -1100,6 +1140,12 @@ func (d *Downloader) findAncestor(p *peer) (uint64, error) {
}
}
}
}
}
}
// Ensure valid ancestry and return
if
int64
(
start
)
<=
floor
{
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"%v: potential rewrite attack: #%d [%x…] <= #%d limit"
,
p
,
start
,
hash
[
:
4
],
floor
)
return
0
,
errInvalidAncestor
}
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"%v: common ancestor: #%d [%x…]"
,
p
,
start
,
hash
[
:
4
])
return
start
,
nil
return
start
,
nil
}
}
...
...
eth/downloader/downloader_test.go
View file @
39ce85cf
This diff is collapsed.
Click to expand it.
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