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
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 (
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/params"
"github.com/rcrowley/go-metrics"
)
...
...
@@ -45,6 +46,8 @@ var (
MaxReceiptFetch
=
256
// Amount of transaction receipts 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
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
...
...
@@ -79,6 +82,7 @@ var (
errEmptyHeaderSet
=
errors
.
New
(
"empty header set by peer"
)
errPeersUnavailable
=
errors
.
New
(
"no peers available or all tried for download"
)
errAlreadyInPool
=
errors
.
New
(
"hash already in pool"
)
errInvalidAncestor
=
errors
.
New
(
"retrieved ancestor is invalid"
)
errInvalidChain
=
errors
.
New
(
"retrieved hash chain is invalid"
)
errInvalidBlock
=
errors
.
New
(
"retrieved block 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
case
errBusy
:
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
)
d
.
dropPeer
(
id
)
...
...
@@ -353,7 +357,7 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash, td *big.Int) (err e
if
err
!=
nil
{
return
err
}
origin
,
err
:=
d
.
findAncestor61
(
p
)
origin
,
err
:=
d
.
findAncestor61
(
p
,
latest
)
if
err
!=
nil
{
return
err
}
...
...
@@ -380,7 +384,7 @@ func (d *Downloader) syncWithPeer(p *peer, hash common.Hash, td *big.Int) (err e
if
err
!=
nil
{
return
err
}
origin
,
err
:=
d
.
findAncestor
(
p
)
origin
,
err
:=
d
.
findAncestor
(
p
,
latest
)
if
err
!=
nil
{
return
err
}
...
...
@@ -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.
// 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.
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
)
// Request out head blocks to short circuit ancestor location
head
:=
d
.
headBlock
()
.
NumberU64
()
// Figure out the valid ancestor range to prevent rewrite attacks
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
if
from
<
0
{
from
=
0
...
...
@@ -600,11 +612,18 @@ func (d *Downloader) findAncestor61(p *peer) (uint64, error) {
}
// If the head fetch already found an ancestor, return
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
])
return
number
,
nil
}
// Ancestor not found, we need to binary search over our chain
start
,
end
:=
uint64
(
0
),
head
if
floor
>
0
{
start
=
uint64
(
floor
)
}
for
start
+
1
<
end
{
// Split our chain interval in two, and request the hash to cross check
check
:=
(
start
+
end
)
/
2
...
...
@@ -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
}
...
...
@@ -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.
// 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
*
peer
)
(
uint64
,
error
)
{
func
(
d
*
Downloader
)
findAncestor
(
p
*
peer
,
height
uint64
)
(
uint64
,
error
)
{
glog
.
V
(
logger
.
Debug
)
.
Infof
(
"%v: looking for common ancestor"
,
p
)
//
Request our head headers to short circuit ancestor location
head
:=
d
.
headHeader
()
.
Number
.
Uint64
()
//
Figure out the valid ancestor range to prevent rewrite attacks
floor
,
ceil
:=
int64
(
-
1
),
d
.
headHeader
()
.
Number
.
Uint64
()
if
d
.
mode
==
FullSync
{
head
=
d
.
headBlock
()
.
NumberU64
()
ceil
=
d
.
headBlock
()
.
NumberU64
()
}
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
if
from
<
0
{
...
...
@@ -1040,11 +1073,18 @@ func (d *Downloader) findAncestor(p *peer) (uint64, error) {
}
// If the head fetch already found an ancestor, return
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
])
return
number
,
nil
}
// Ancestor not found, we need to binary search over our chain
start
,
end
:=
uint64
(
0
),
head
if
floor
>
0
{
start
=
uint64
(
floor
)
}
for
start
+
1
<
end
{
// Split our chain interval in two, and request the hash to cross check
check
:=
(
start
+
end
)
/
2
...
...
@@ -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
}
...
...
eth/downloader/downloader_test.go
View file @
39ce85cf
...
...
@@ -43,8 +43,9 @@ var (
genesis
=
core
.
GenesisBlockForTesting
(
testdb
,
testAddress
,
big
.
NewInt
(
1000000000
))
)
// Reduce
the block cache limit, otherwise the tests will be very heavy
.
// Reduce
some of the parameters to make the tester faster
.
func
init
()
{
MaxForkAncestry
=
uint64
(
10000
)
blockCacheLimit
=
1024
}
...
...
@@ -52,11 +53,15 @@ func init() {
// the returned hash chain is ordered head->parent. In addition, every 3rd block
// contains a transaction and every 5th an uncle to allow testing correct block
// reassembly.
func
makeChain
(
n
int
,
seed
byte
,
parent
*
types
.
Block
,
parentReceipts
types
.
Receipts
)
([]
common
.
Hash
,
map
[
common
.
Hash
]
*
types
.
Header
,
map
[
common
.
Hash
]
*
types
.
Block
,
map
[
common
.
Hash
]
types
.
Receipts
)
{
func
makeChain
(
n
int
,
seed
byte
,
parent
*
types
.
Block
,
parentReceipts
types
.
Receipts
,
heavy
bool
)
([]
common
.
Hash
,
map
[
common
.
Hash
]
*
types
.
Header
,
map
[
common
.
Hash
]
*
types
.
Block
,
map
[
common
.
Hash
]
types
.
Receipts
)
{
// Generate the block chain
blocks
,
receipts
:=
core
.
GenerateChain
(
parent
,
testdb
,
n
,
func
(
i
int
,
block
*
core
.
BlockGen
)
{
block
.
SetCoinbase
(
common
.
Address
{
seed
})
// If a heavy chain is requested, delay blocks to raise difficulty
if
heavy
{
block
.
OffsetTime
(
-
1
)
}
// If the block number is multiple of 3, send a bonus transaction to the miner
if
parent
==
genesis
&&
i
%
3
==
0
{
tx
,
err
:=
types
.
NewTransaction
(
block
.
TxNonce
(
testAddress
),
common
.
Address
{
seed
},
big
.
NewInt
(
1000
),
params
.
TxGas
,
nil
,
nil
)
.
SignECDSA
(
testKey
)
...
...
@@ -97,15 +102,19 @@ func makeChain(n int, seed byte, parent *types.Block, parentReceipts types.Recei
// makeChainFork creates two chains of length n, such that h1[:f] and
// h2[:f] are different but have a common suffix of length n-f.
func
makeChainFork
(
n
,
f
int
,
parent
*
types
.
Block
,
parentReceipts
types
.
Receipts
)
([]
common
.
Hash
,
[]
common
.
Hash
,
map
[
common
.
Hash
]
*
types
.
Header
,
map
[
common
.
Hash
]
*
types
.
Header
,
map
[
common
.
Hash
]
*
types
.
Block
,
map
[
common
.
Hash
]
*
types
.
Block
,
map
[
common
.
Hash
]
types
.
Receipts
,
map
[
common
.
Hash
]
types
.
Receipts
)
{
func
makeChainFork
(
n
,
f
int
,
parent
*
types
.
Block
,
parentReceipts
types
.
Receipts
,
balanced
bool
)
([]
common
.
Hash
,
[]
common
.
Hash
,
map
[
common
.
Hash
]
*
types
.
Header
,
map
[
common
.
Hash
]
*
types
.
Header
,
map
[
common
.
Hash
]
*
types
.
Block
,
map
[
common
.
Hash
]
*
types
.
Block
,
map
[
common
.
Hash
]
types
.
Receipts
,
map
[
common
.
Hash
]
types
.
Receipts
)
{
// Create the common suffix
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
n
-
f
,
0
,
parent
,
parentReceipts
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
n
-
f
,
0
,
parent
,
parentReceipts
,
false
)
// Create the forks
hashes1
,
headers1
,
blocks1
,
receipts1
:=
makeChain
(
f
,
1
,
blocks
[
hashes
[
0
]],
receipts
[
hashes
[
0
]])
// Create the forks
, making the second heavyer if non balanced forks were requested
hashes1
,
headers1
,
blocks1
,
receipts1
:=
makeChain
(
f
,
1
,
blocks
[
hashes
[
0
]],
receipts
[
hashes
[
0
]]
,
false
)
hashes1
=
append
(
hashes1
,
hashes
[
1
:
]
...
)
hashes2
,
headers2
,
blocks2
,
receipts2
:=
makeChain
(
f
,
2
,
blocks
[
hashes
[
0
]],
receipts
[
hashes
[
0
]])
heavy
:=
false
if
!
balanced
{
heavy
=
true
}
hashes2
,
headers2
,
blocks2
,
receipts2
:=
makeChain
(
f
,
2
,
blocks
[
hashes
[
0
]],
receipts
[
hashes
[
0
]],
heavy
)
hashes2
=
append
(
hashes2
,
hashes
[
1
:
]
...
)
for
hash
,
header
:=
range
headers
{
...
...
@@ -712,7 +721,7 @@ func testCanonicalSynchronisation(t *testing.T, protocol int, mode SyncMode) {
// Create a small enough block chain to download
targetBlocks
:=
blockCacheLimit
-
15
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
,
false
)
tester
:=
newTester
()
tester
.
newPeer
(
"peer"
,
protocol
,
hashes
,
headers
,
blocks
,
receipts
)
...
...
@@ -736,7 +745,7 @@ func TestThrottling64Fast(t *testing.T) { testThrottling(t, 64, FastSync) }
func
testThrottling
(
t
*
testing
.
T
,
protocol
int
,
mode
SyncMode
)
{
// Create a long block chain to download and the tester
targetBlocks
:=
8
*
blockCacheLimit
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
,
false
)
tester
:=
newTester
()
tester
.
newPeer
(
"peer"
,
protocol
,
hashes
,
headers
,
blocks
,
receipts
)
...
...
@@ -810,20 +819,20 @@ func testThrottling(t *testing.T, protocol int, mode SyncMode) {
// Tests that simple synchronization against a forked chain works correctly. In
// this test common ancestor lookup should *not* be short circuited, and a full
// binary search should be executed.
func
TestForkedSync
hronisation61
(
t
*
testing
.
T
)
{
testForkedSynchronisation
(
t
,
61
,
FullSync
)
}
func
TestForkedSync
hronisation62
(
t
*
testing
.
T
)
{
testForkedSynchronisation
(
t
,
62
,
FullSync
)
}
func
TestForkedSync
hronisation63Full
(
t
*
testing
.
T
)
{
testForkedSynchronisation
(
t
,
63
,
FullSync
)
}
func
TestForkedSync
hronisation63Fast
(
t
*
testing
.
T
)
{
testForkedSynchronisation
(
t
,
63
,
FastSync
)
}
func
TestForkedSync
hronisation64Full
(
t
*
testing
.
T
)
{
testForkedSynchronisation
(
t
,
64
,
FullSync
)
}
func
TestForkedSync
hronisation64Fast
(
t
*
testing
.
T
)
{
testForkedSynchronisation
(
t
,
64
,
FastSync
)
}
func
TestForkedSync
hronisation64Light
(
t
*
testing
.
T
)
{
testForkedSynchronisation
(
t
,
64
,
LightSync
)
}
func
testForkedSync
hronisation
(
t
*
testing
.
T
,
protocol
int
,
mode
SyncMode
)
{
func
TestForkedSync
61
(
t
*
testing
.
T
)
{
testForkedSync
(
t
,
61
,
FullSync
)
}
func
TestForkedSync
62
(
t
*
testing
.
T
)
{
testForkedSync
(
t
,
62
,
FullSync
)
}
func
TestForkedSync
63Full
(
t
*
testing
.
T
)
{
testForkedSync
(
t
,
63
,
FullSync
)
}
func
TestForkedSync
63Fast
(
t
*
testing
.
T
)
{
testForkedSync
(
t
,
63
,
FastSync
)
}
func
TestForkedSync
64Full
(
t
*
testing
.
T
)
{
testForkedSync
(
t
,
64
,
FullSync
)
}
func
TestForkedSync
64Fast
(
t
*
testing
.
T
)
{
testForkedSync
(
t
,
64
,
FastSync
)
}
func
TestForkedSync
64Light
(
t
*
testing
.
T
)
{
testForkedSync
(
t
,
64
,
LightSync
)
}
func
testForkedSync
(
t
*
testing
.
T
,
protocol
int
,
mode
SyncMode
)
{
t
.
Parallel
()
// Create a long enough forked chain
common
,
fork
:=
MaxHashFetch
,
2
*
MaxHashFetch
hashesA
,
hashesB
,
headersA
,
headersB
,
blocksA
,
blocksB
,
receiptsA
,
receiptsB
:=
makeChainFork
(
common
+
fork
,
fork
,
genesis
,
nil
)
hashesA
,
hashesB
,
headersA
,
headersB
,
blocksA
,
blocksB
,
receiptsA
,
receiptsB
:=
makeChainFork
(
common
+
fork
,
fork
,
genesis
,
nil
,
true
)
tester
:=
newTester
()
tester
.
newPeer
(
"fork A"
,
protocol
,
hashesA
,
headersA
,
blocksA
,
receiptsA
)
...
...
@@ -842,6 +851,40 @@ func testForkedSynchronisation(t *testing.T, protocol int, mode SyncMode) {
assertOwnForkedChain
(
t
,
tester
,
common
+
1
,
[]
int
{
common
+
fork
+
1
,
common
+
fork
+
1
})
}
// Tests that synchronising against a much shorter but much heavyer fork works
// corrently and is not dropped.
func
TestHeavyForkedSync61
(
t
*
testing
.
T
)
{
testHeavyForkedSync
(
t
,
61
,
FullSync
)
}
func
TestHeavyForkedSync62
(
t
*
testing
.
T
)
{
testHeavyForkedSync
(
t
,
62
,
FullSync
)
}
func
TestHeavyForkedSync63Full
(
t
*
testing
.
T
)
{
testHeavyForkedSync
(
t
,
63
,
FullSync
)
}
func
TestHeavyForkedSync63Fast
(
t
*
testing
.
T
)
{
testHeavyForkedSync
(
t
,
63
,
FastSync
)
}
func
TestHeavyForkedSync64Full
(
t
*
testing
.
T
)
{
testHeavyForkedSync
(
t
,
64
,
FullSync
)
}
func
TestHeavyForkedSync64Fast
(
t
*
testing
.
T
)
{
testHeavyForkedSync
(
t
,
64
,
FastSync
)
}
func
TestHeavyForkedSync64Light
(
t
*
testing
.
T
)
{
testHeavyForkedSync
(
t
,
64
,
LightSync
)
}
func
testHeavyForkedSync
(
t
*
testing
.
T
,
protocol
int
,
mode
SyncMode
)
{
t
.
Parallel
()
// Create a long enough forked chain
common
,
fork
:=
MaxHashFetch
,
4
*
MaxHashFetch
hashesA
,
hashesB
,
headersA
,
headersB
,
blocksA
,
blocksB
,
receiptsA
,
receiptsB
:=
makeChainFork
(
common
+
fork
,
fork
,
genesis
,
nil
,
false
)
tester
:=
newTester
()
tester
.
newPeer
(
"light"
,
protocol
,
hashesA
,
headersA
,
blocksA
,
receiptsA
)
tester
.
newPeer
(
"heavy"
,
protocol
,
hashesB
[
fork
/
2
:
],
headersB
,
blocksB
,
receiptsB
)
// Synchronise with the peer and make sure all blocks were retrieved
if
err
:=
tester
.
sync
(
"light"
,
nil
,
mode
);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
assertOwnChain
(
t
,
tester
,
common
+
fork
+
1
)
// Synchronise with the second peer and make sure that fork is pulled too
if
err
:=
tester
.
sync
(
"heavy"
,
nil
,
mode
);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
assertOwnForkedChain
(
t
,
tester
,
common
+
1
,
[]
int
{
common
+
fork
+
1
,
common
+
fork
/
2
+
1
})
}
// Tests that an inactive downloader will not accept incoming hashes and blocks.
func
TestInactiveDownloader61
(
t
*
testing
.
T
)
{
t
.
Parallel
()
...
...
@@ -856,6 +899,74 @@ func TestInactiveDownloader61(t *testing.T) {
}
}
// Tests that chain forks are contained within a certain interval of the current
// chain head, ensuring that malicious peers cannot waste resources by feeding
// long dead chains.
func
TestBoundedForkedSync61
(
t
*
testing
.
T
)
{
testBoundedForkedSync
(
t
,
61
,
FullSync
)
}
func
TestBoundedForkedSync62
(
t
*
testing
.
T
)
{
testBoundedForkedSync
(
t
,
62
,
FullSync
)
}
func
TestBoundedForkedSync63Full
(
t
*
testing
.
T
)
{
testBoundedForkedSync
(
t
,
63
,
FullSync
)
}
func
TestBoundedForkedSync63Fast
(
t
*
testing
.
T
)
{
testBoundedForkedSync
(
t
,
63
,
FastSync
)
}
func
TestBoundedForkedSync64Full
(
t
*
testing
.
T
)
{
testBoundedForkedSync
(
t
,
64
,
FullSync
)
}
func
TestBoundedForkedSync64Fast
(
t
*
testing
.
T
)
{
testBoundedForkedSync
(
t
,
64
,
FastSync
)
}
func
TestBoundedForkedSync64Light
(
t
*
testing
.
T
)
{
testBoundedForkedSync
(
t
,
64
,
LightSync
)
}
func
testBoundedForkedSync
(
t
*
testing
.
T
,
protocol
int
,
mode
SyncMode
)
{
t
.
Parallel
()
// Create a long enough forked chain
common
,
fork
:=
13
,
int
(
MaxForkAncestry
+
17
)
hashesA
,
hashesB
,
headersA
,
headersB
,
blocksA
,
blocksB
,
receiptsA
,
receiptsB
:=
makeChainFork
(
common
+
fork
,
fork
,
genesis
,
nil
,
true
)
tester
:=
newTester
()
tester
.
newPeer
(
"original"
,
protocol
,
hashesA
,
headersA
,
blocksA
,
receiptsA
)
tester
.
newPeer
(
"rewriter"
,
protocol
,
hashesB
,
headersB
,
blocksB
,
receiptsB
)
// Synchronise with the peer and make sure all blocks were retrieved
if
err
:=
tester
.
sync
(
"original"
,
nil
,
mode
);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
assertOwnChain
(
t
,
tester
,
common
+
fork
+
1
)
// Synchronise with the second peer and ensure that the fork is rejected to being too old
if
err
:=
tester
.
sync
(
"rewriter"
,
nil
,
mode
);
err
!=
errInvalidAncestor
{
t
.
Fatalf
(
"sync failure mismatch: have %v, want %v"
,
err
,
errInvalidAncestor
)
}
}
// Tests that chain forks are contained within a certain interval of the current
// chain head for short but heavy forks too. These are a bit special because they
// take different ancestor lookup paths.
func
TestBoundedHeavyForkedSync61
(
t
*
testing
.
T
)
{
testBoundedHeavyForkedSync
(
t
,
61
,
FullSync
)
}
func
TestBoundedHeavyForkedSync62
(
t
*
testing
.
T
)
{
testBoundedHeavyForkedSync
(
t
,
62
,
FullSync
)
}
func
TestBoundedHeavyForkedSync63Full
(
t
*
testing
.
T
)
{
testBoundedHeavyForkedSync
(
t
,
63
,
FullSync
)
}
func
TestBoundedHeavyForkedSync63Fast
(
t
*
testing
.
T
)
{
testBoundedHeavyForkedSync
(
t
,
63
,
FastSync
)
}
func
TestBoundedHeavyForkedSync64Full
(
t
*
testing
.
T
)
{
testBoundedHeavyForkedSync
(
t
,
64
,
FullSync
)
}
func
TestBoundedHeavyForkedSync64Fast
(
t
*
testing
.
T
)
{
testBoundedHeavyForkedSync
(
t
,
64
,
FastSync
)
}
func
TestBoundedHeavyForkedSync64Light
(
t
*
testing
.
T
)
{
testBoundedHeavyForkedSync
(
t
,
64
,
LightSync
)
}
func
testBoundedHeavyForkedSync
(
t
*
testing
.
T
,
protocol
int
,
mode
SyncMode
)
{
t
.
Parallel
()
// Create a long enough forked chain
common
,
fork
:=
13
,
int
(
MaxForkAncestry
+
17
)
hashesA
,
hashesB
,
headersA
,
headersB
,
blocksA
,
blocksB
,
receiptsA
,
receiptsB
:=
makeChainFork
(
common
+
fork
,
fork
,
genesis
,
nil
,
false
)
tester
:=
newTester
()
tester
.
newPeer
(
"original"
,
protocol
,
hashesA
,
headersA
,
blocksA
,
receiptsA
)
tester
.
newPeer
(
"heavy-rewriter"
,
protocol
,
hashesB
[
MaxForkAncestry
-
17
:
],
headersB
,
blocksB
,
receiptsB
)
// Root the fork below the ancestor limit
// Synchronise with the peer and make sure all blocks were retrieved
if
err
:=
tester
.
sync
(
"original"
,
nil
,
mode
);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
assertOwnChain
(
t
,
tester
,
common
+
fork
+
1
)
// Synchronise with the second peer and ensure that the fork is rejected to being too old
if
err
:=
tester
.
sync
(
"heavy-rewriter"
,
nil
,
mode
);
err
!=
errInvalidAncestor
{
t
.
Fatalf
(
"sync failure mismatch: have %v, want %v"
,
err
,
errInvalidAncestor
)
}
}
// Tests that an inactive downloader will not accept incoming block headers and
// bodies.
func
TestInactiveDownloader62
(
t
*
testing
.
T
)
{
...
...
@@ -909,7 +1020,7 @@ func testCancel(t *testing.T, protocol int, mode SyncMode) {
if
targetBlocks
>=
MaxHeaderFetch
{
targetBlocks
=
MaxHeaderFetch
-
15
}
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
,
false
)
tester
:=
newTester
()
tester
.
newPeer
(
"peer"
,
protocol
,
hashes
,
headers
,
blocks
,
receipts
)
...
...
@@ -944,7 +1055,7 @@ func testMultiSynchronisation(t *testing.T, protocol int, mode SyncMode) {
// Create various peers with various parts of the chain
targetPeers
:=
8
targetBlocks
:=
targetPeers
*
blockCacheLimit
-
15
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
,
false
)
tester
:=
newTester
()
for
i
:=
0
;
i
<
targetPeers
;
i
++
{
...
...
@@ -972,7 +1083,7 @@ func testMultiProtoSync(t *testing.T, protocol int, mode SyncMode) {
// Create a small enough block chain to download
targetBlocks
:=
blockCacheLimit
-
15
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
,
false
)
// Create peers of every type
tester
:=
newTester
()
...
...
@@ -1010,7 +1121,7 @@ func testEmptyShortCircuit(t *testing.T, protocol int, mode SyncMode) {
// Create a block chain to download
targetBlocks
:=
2
*
blockCacheLimit
-
15
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
,
false
)
tester
:=
newTester
()
tester
.
newPeer
(
"peer"
,
protocol
,
hashes
,
headers
,
blocks
,
receipts
)
...
...
@@ -1063,7 +1174,7 @@ func testMissingHeaderAttack(t *testing.T, protocol int, mode SyncMode) {
// Create a small enough block chain to download
targetBlocks
:=
blockCacheLimit
-
15
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
,
false
)
tester
:=
newTester
()
...
...
@@ -1095,7 +1206,7 @@ func TestShiftedHeaderAttack64Light(t *testing.T) { testShiftedHeaderAttack(t, 6
func
testShiftedHeaderAttack
(
t
*
testing
.
T
,
protocol
int
,
mode
SyncMode
)
{
// Create a small enough block chain to download
targetBlocks
:=
blockCacheLimit
-
15
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
,
false
)
tester
:=
newTester
()
...
...
@@ -1126,7 +1237,7 @@ func TestInvalidHeaderRollback64Light(t *testing.T) { testInvalidHeaderRollback(
func
testInvalidHeaderRollback
(
t
*
testing
.
T
,
protocol
int
,
mode
SyncMode
)
{
// Create a small enough block chain to download
targetBlocks
:=
3
*
fsHeaderSafetyNet
+
fsMinFullBlocks
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
,
false
)
tester
:=
newTester
()
...
...
@@ -1217,7 +1328,7 @@ func testHighTDStarvationAttack(t *testing.T, protocol int, mode SyncMode) {
t
.
Parallel
()
tester
:=
newTester
()
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
0
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
0
,
0
,
genesis
,
nil
,
false
)
tester
.
newPeer
(
"attack"
,
protocol
,
[]
common
.
Hash
{
hashes
[
0
]},
headers
,
blocks
,
receipts
)
if
err
:=
tester
.
sync
(
"attack"
,
big
.
NewInt
(
1000000
),
mode
);
err
!=
errStallingPeer
{
...
...
@@ -1247,6 +1358,7 @@ func testBlockHeaderAttackerDropping(t *testing.T, protocol int) {
{
errEmptyHashSet
,
true
},
// No hashes were returned as a response, drop as it's a dead end
{
errEmptyHeaderSet
,
true
},
// No headers were returned as a response, drop as it's a dead end
{
errPeersUnavailable
,
true
},
// Nobody had the advertised blocks, drop the advertiser
{
errInvalidAncestor
,
true
},
// Agreed upon ancestor is not acceptable, drop the chain rewriter
{
errInvalidChain
,
true
},
// Hash chain was detected as invalid, definitely drop
{
errInvalidBlock
,
false
},
// A bad peer was detected, but not the sync origin
{
errInvalidBody
,
false
},
// A bad peer was detected, but not the sync origin
...
...
@@ -1294,7 +1406,7 @@ func testSyncProgress(t *testing.T, protocol int, mode SyncMode) {
// Create a small enough block chain to download
targetBlocks
:=
blockCacheLimit
-
15
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
,
false
)
// Set a sync init hook to catch progress changes
starting
:=
make
(
chan
struct
{})
...
...
@@ -1366,7 +1478,7 @@ func testForkedSyncProgress(t *testing.T, protocol int, mode SyncMode) {
// Create a forked chain to simulate origin revertal
common
,
fork
:=
MaxHashFetch
,
2
*
MaxHashFetch
hashesA
,
hashesB
,
headersA
,
headersB
,
blocksA
,
blocksB
,
receiptsA
,
receiptsB
:=
makeChainFork
(
common
+
fork
,
fork
,
genesis
,
nil
)
hashesA
,
hashesB
,
headersA
,
headersB
,
blocksA
,
blocksB
,
receiptsA
,
receiptsB
:=
makeChainFork
(
common
+
fork
,
fork
,
genesis
,
nil
,
true
)
// Set a sync init hook to catch progress changes
starting
:=
make
(
chan
struct
{})
...
...
@@ -1441,7 +1553,7 @@ func testFailedSyncProgress(t *testing.T, protocol int, mode SyncMode) {
// Create a small enough block chain to download
targetBlocks
:=
blockCacheLimit
-
15
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
,
0
,
genesis
,
nil
,
false
)
// Set a sync init hook to catch progress changes
starting
:=
make
(
chan
struct
{})
...
...
@@ -1517,7 +1629,7 @@ func testFakedSyncProgress(t *testing.T, protocol int, mode SyncMode) {
// Create a small block chain
targetBlocks
:=
blockCacheLimit
-
15
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
+
3
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
targetBlocks
+
3
,
0
,
genesis
,
nil
,
false
)
// Set a sync init hook to catch progress changes
starting
:=
make
(
chan
struct
{})
...
...
@@ -1590,7 +1702,7 @@ func TestDeliverHeadersHang64Light(t *testing.T) { testDeliverHeadersHang(t, 64,
func
testDeliverHeadersHang
(
t
*
testing
.
T
,
protocol
int
,
mode
SyncMode
)
{
t
.
Parallel
()
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
5
,
0
,
genesis
,
nil
)
hashes
,
headers
,
blocks
,
receipts
:=
makeChain
(
5
,
0
,
genesis
,
nil
,
false
)
fakeHeads
:=
[]
*
types
.
Header
{{},
{},
{},
{}}
for
i
:=
0
;
i
<
200
;
i
++
{
tester
:=
newTester
()
...
...
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