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
51b2f162
Unverified
Commit
51b2f162
authored
Nov 12, 2018
by
Martin Holst Swende
Committed by
Péter Szilágyi
Nov 16, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
downloader: different sync strategy
parent
68be45e5
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
155 additions
and
39 deletions
+155
-39
downloader.go
eth/downloader/downloader.go
+79
-39
downloader_test.go
eth/downloader/downloader_test.go
+76
-0
No files found.
eth/downloader/downloader.go
View file @
51b2f162
...
...
@@ -430,7 +430,7 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.I
}
height
:=
latest
.
Number
.
Uint64
()
origin
,
err
:=
d
.
findAncestor
(
p
,
heigh
t
)
origin
,
err
:=
d
.
findAncestor
(
p
,
lates
t
)
if
err
!=
nil
{
return
err
}
...
...
@@ -587,41 +587,85 @@ func (d *Downloader) fetchHeight(p *peerConnection) (*types.Header, error) {
}
}
// calculateRequestSpan calculates what headers to request from a peer when trying to determine the
// common ancestor.
// It returns parameters to be used for peer.RequestHeadersByNumber:
// from - starting block number
// count - number of headers to request
// skip - number of headers to skip
// and also returns 'max', the last block which is expected to be returned by the remote peers,
// given the (from,count,skip)
func
calculateRequestSpan
(
remoteHeight
,
localHeight
uint64
)
(
int64
,
int
,
int
,
uint64
)
{
var
(
from
int
count
int
MaxCount
=
MaxHeaderFetch
/
16
)
// requestHead is the highest block that we will ask for. If requestHead is not offset,
// the highest block that we will get is 16 blocks back from head, which means we
// will fetch 14 or 15 blocks unnecessarily in the case the height difference
// between us and the peer is 1-2 blocks, which is most common
requestHead
:=
int
(
remoteHeight
)
-
1
if
requestHead
<
0
{
requestHead
=
0
}
// requestBottom is the lowest block we want included in the query
// Ideally, we want to include just below own head
requestBottom
:=
int
(
localHeight
-
1
)
if
requestBottom
<
0
{
requestBottom
=
0
}
totalSpan
:=
requestHead
-
requestBottom
span
:=
1
+
totalSpan
/
MaxCount
if
span
<
2
{
span
=
2
}
if
span
>
16
{
span
=
16
}
count
=
1
+
totalSpan
/
span
if
count
>
MaxCount
{
count
=
MaxCount
}
if
count
<
2
{
count
=
2
}
from
=
requestHead
-
(
count
-
1
)
*
span
if
from
<
0
{
from
=
0
}
max
:=
from
+
(
count
-
1
)
*
span
return
int64
(
from
),
count
,
span
-
1
,
uint64
(
max
)
}
// findAncestor tries to locate the common ancestor link of the local chain and
// a remote peers blockchain. In the general case when our node was in sync and
// 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
// the head links match), we do a binary search to find the common ancestor.
func
(
d
*
Downloader
)
findAncestor
(
p
*
peerConnection
,
height
uint64
)
(
uint64
,
error
)
{
func
(
d
*
Downloader
)
findAncestor
(
p
*
peerConnection
,
remoteHeader
*
types
.
Header
)
(
uint64
,
error
)
{
// Figure out the valid ancestor range to prevent rewrite attacks
floor
,
ceil
:=
int64
(
-
1
),
d
.
lightchain
.
CurrentHeader
()
.
Number
.
Uint64
()
if
d
.
mode
==
FullSync
{
ceil
=
d
.
blockchain
.
CurrentBlock
()
.
NumberU64
()
}
else
if
d
.
mode
==
FastSync
{
ceil
=
d
.
blockchain
.
CurrentFastBlock
()
.
NumberU64
()
var
(
floor
=
int64
(
-
1
)
localHeight
uint64
remoteHeight
=
remoteHeader
.
Number
.
Uint64
()
)
switch
d
.
mode
{
case
FullSync
:
localHeight
=
d
.
blockchain
.
CurrentBlock
()
.
NumberU64
()
case
FastSync
:
localHeight
=
d
.
blockchain
.
CurrentFastBlock
()
.
NumberU64
()
default
:
localHeight
=
d
.
lightchain
.
CurrentHeader
()
.
Number
.
Uint64
()
}
if
ceil
>=
MaxForkAncestry
{
floor
=
int64
(
ceil
-
MaxForkAncestry
)
p
.
log
.
Debug
(
"Looking for common ancestor"
,
"local"
,
localHeight
,
"remote"
,
remoteHeight
)
if
localHeight
>=
MaxForkAncestry
{
floor
=
int64
(
localHeight
-
MaxForkAncestry
)
}
p
.
log
.
Debug
(
"Looking for common ancestor"
,
"local"
,
ceil
,
"remote"
,
height
)
// Request the topmost blocks to short circuit binary ancestor lookup
head
:=
ceil
if
head
>
height
{
head
=
height
}
from
:=
int64
(
head
)
-
int64
(
MaxHeaderFetch
)
if
from
<
0
{
from
=
0
}
// Span out with 15 block gaps into the future to catch bad head reports
limit
:=
2
*
MaxHeaderFetch
/
16
count
:=
1
+
int
((
int64
(
ceil
)
-
from
)
/
16
)
if
count
>
limit
{
count
=
limit
}
go
p
.
peer
.
RequestHeadersByNumber
(
uint64
(
from
),
count
,
15
,
false
)
from
,
count
,
skip
,
max
:=
calculateRequestSpan
(
remoteHeight
,
localHeight
)
go
p
.
peer
.
RequestHeadersByNumber
(
uint64
(
from
),
count
,
skip
,
false
)
// Wait for the remote response to the head fetch
number
,
hash
:=
uint64
(
0
),
common
.
Hash
{}
...
...
@@ -647,9 +691,10 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
return
0
,
errEmptyHeaderSet
}
// Make sure the peer's reply conforms to the request
for
i
:=
0
;
i
<
len
(
headers
);
i
++
{
if
number
:=
headers
[
i
]
.
Number
.
Int64
();
number
!=
from
+
int64
(
i
)
*
16
{
p
.
log
.
Warn
(
"Head headers broke chain ordering"
,
"index"
,
i
,
"requested"
,
from
+
int64
(
i
)
*
16
,
"received"
,
number
)
for
i
,
header
:=
range
headers
{
expectNumber
:=
from
+
int64
(
i
)
*
int64
((
skip
+
1
))
if
number
:=
header
.
Number
.
Int64
();
number
!=
expectNumber
{
p
.
log
.
Warn
(
"Head headers broke chain ordering"
,
"index"
,
i
,
"requested"
,
expectNumber
,
"received"
,
number
)
return
0
,
errInvalidChain
}
}
...
...
@@ -657,20 +702,15 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
finished
=
true
for
i
:=
len
(
headers
)
-
1
;
i
>=
0
;
i
--
{
// Skip any headers that underflow/overflow our requested set
if
headers
[
i
]
.
Number
.
Int64
()
<
from
||
headers
[
i
]
.
Number
.
Uint64
()
>
ceil
{
if
headers
[
i
]
.
Number
.
Int64
()
<
from
||
headers
[
i
]
.
Number
.
Uint64
()
>
max
{
continue
}
// Otherwise check if we already know the header or not
h
:=
headers
[
i
]
.
Hash
()
n
:=
headers
[
i
]
.
Number
.
Uint64
()
if
(
d
.
mode
==
FullSync
&&
d
.
blockchain
.
HasBlock
(
h
,
n
))
||
(
d
.
mode
!=
FullSync
&&
d
.
lightchain
.
HasHeader
(
h
,
n
))
{
if
(
d
.
mode
==
FullSync
&&
d
.
blockchain
.
HasBlock
(
h
,
n
))
||
(
d
.
mode
!=
FullSync
&&
d
.
lightchain
.
HasHeader
(
h
,
n
))
{
number
,
hash
=
n
,
h
// If every header is known, even future ones, the peer straight out lied about its head
if
number
>
height
&&
i
==
limit
-
1
{
p
.
log
.
Warn
(
"Lied about chain head"
,
"reported"
,
height
,
"found"
,
number
)
return
0
,
errStallingPeer
}
break
}
}
...
...
@@ -694,7 +734,7 @@ func (d *Downloader) findAncestor(p *peerConnection, height uint64) (uint64, err
return
number
,
nil
}
// Ancestor not found, we need to binary search over our chain
start
,
end
:=
uint64
(
0
),
head
start
,
end
:=
uint64
(
0
),
remoteHeight
if
floor
>
0
{
start
=
uint64
(
floor
)
}
...
...
eth/downloader/downloader_test.go
View file @
51b2f162
...
...
@@ -20,6 +20,7 @@ import (
"errors"
"fmt"
"math/big"
"strings"
"sync"
"sync/atomic"
"testing"
...
...
@@ -1479,3 +1480,78 @@ func (ftp *floodingTestPeer) RequestHeadersByNumber(from uint64, count, skip int
}
return
nil
}
func
TestRemoteHeaderRequestSpan
(
t
*
testing
.
T
)
{
testCases
:=
[]
struct
{
remoteHeight
uint64
localHeight
uint64
expected
[]
int
}{
// Remote is way higher. We should ask for the remote head and go backwards
{
1500
,
1000
,
[]
int
{
1323
,
1339
,
1355
,
1371
,
1387
,
1403
,
1419
,
1435
,
1451
,
1467
,
1483
,
1499
},
},
{
15000
,
13006
,
[]
int
{
14823
,
14839
,
14855
,
14871
,
14887
,
14903
,
14919
,
14935
,
14951
,
14967
,
14983
,
14999
},
},
//Remote is pretty close to us. We don't have to fetch as many
{
1200
,
1150
,
[]
int
{
1149
,
1154
,
1159
,
1164
,
1169
,
1174
,
1179
,
1184
,
1189
,
1194
,
1199
},
},
// Remote is equal to us (so on a fork with higher td)
// We should get the closest couple of ancestors
{
1500
,
1500
,
[]
int
{
1497
,
1499
},
},
// We're higher than the remote! Odd
{
1000
,
1500
,
[]
int
{
997
,
999
},
},
// Check some weird edgecases that it behaves somewhat rationally
{
0
,
1500
,
[]
int
{
0
,
2
},
},
{
6000000
,
0
,
[]
int
{
5999823
,
5999839
,
5999855
,
5999871
,
5999887
,
5999903
,
5999919
,
5999935
,
5999951
,
5999967
,
5999983
,
5999999
},
},
{
0
,
0
,
[]
int
{
0
,
2
},
},
}
reqs
:=
func
(
from
,
count
,
span
int
)
[]
int
{
var
r
[]
int
num
:=
from
for
len
(
r
)
<
count
{
r
=
append
(
r
,
num
)
num
+=
span
+
1
}
return
r
}
for
i
,
tt
:=
range
testCases
{
from
,
count
,
span
,
max
:=
calculateRequestSpan
(
tt
.
remoteHeight
,
tt
.
localHeight
)
data
:=
reqs
(
int
(
from
),
count
,
span
)
if
max
!=
uint64
(
data
[
len
(
data
)
-
1
])
{
t
.
Errorf
(
"test %d: wrong last value %d != %d"
,
i
,
data
[
len
(
data
)
-
1
],
max
)
}
failed
:=
false
if
len
(
data
)
!=
len
(
tt
.
expected
)
{
failed
=
true
t
.
Errorf
(
"test %d: length wrong, expected %d got %d"
,
i
,
len
(
tt
.
expected
),
len
(
data
))
}
else
{
for
j
,
n
:=
range
data
{
if
n
!=
tt
.
expected
[
j
]
{
failed
=
true
break
}
}
}
if
failed
{
res
:=
strings
.
Replace
(
fmt
.
Sprint
(
data
),
" "
,
","
,
-
1
)
exp
:=
strings
.
Replace
(
fmt
.
Sprint
(
tt
.
expected
),
" "
,
","
,
-
1
)
fmt
.
Printf
(
"got: %v
\n
"
,
res
)
fmt
.
Printf
(
"exp: %v
\n
"
,
exp
)
t
.
Errorf
(
"test %d: wrong values"
,
i
)
}
}
}
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