Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
whqwjb
go-ethereum
提交
0fc71877
G
go-ethereum
项目概览
whqwjb
/
go-ethereum
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
G
go-ethereum
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
前往新版Gitcode,体验更适合开发者的 AI 搜索 >>
提交
0fc71877
编写于
6月 11, 2015
作者:
P
Péter Szilágyi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
eth/downloader: add valid peer during attacks (check interference)
上级
80833f81
变更
1
显示空白变更内容
内联
并排
Showing
1 changed file
with
140 addition
and
93 deletion
+140
-93
eth/downloader/downloader_test.go
eth/downloader/downloader_test.go
+140
-93
未找到文件。
eth/downloader/downloader_test.go
浏览文件 @
0fc71877
...
@@ -14,23 +14,29 @@ import (
...
@@ -14,23 +14,29 @@ import (
)
)
var
(
var
(
knownHash
=
common
.
Hash
{
1
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
}
knownHash
=
common
.
Hash
{
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
,
1
}
unknownHash
=
common
.
Hash
{
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
,
9
}
unknownHash
=
common
.
Hash
{
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
,
2
}
bannedHash
=
common
.
Hash
{
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
,
5
}
bannedHash
=
common
.
Hash
{
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
,
3
}
genesis
=
createBlock
(
1
,
common
.
Hash
{},
knownHash
)
genesis
=
createBlock
(
1
,
common
.
Hash
{},
knownHash
)
)
)
func
createHashes
(
start
,
amount
int
)
(
hashes
[]
common
.
Hash
)
{
// idCounter is used by the createHashes method the generate deterministic but unique hashes
var
idCounter
=
int64
(
2
)
// #1 is the genesis block
// createHashes generates a batch of hashes rooted at a specific point in the chain.
func
createHashes
(
amount
int
,
root
common
.
Hash
)
(
hashes
[]
common
.
Hash
)
{
hashes
=
make
([]
common
.
Hash
,
amount
+
1
)
hashes
=
make
([]
common
.
Hash
,
amount
+
1
)
hashes
[
len
(
hashes
)
-
1
]
=
knownHash
hashes
[
len
(
hashes
)
-
1
]
=
root
for
i
:=
range
hashes
[
:
len
(
hashes
)
-
1
]
{
for
i
:=
0
;
i
<
len
(
hashes
)
-
1
;
i
++
{
binary
.
BigEndian
.
PutUint64
(
hashes
[
i
][
:
8
],
uint64
(
start
+
i
+
2
))
binary
.
BigEndian
.
PutUint64
(
hashes
[
i
][
:
8
],
uint64
(
idCounter
))
idCounter
++
}
}
return
return
}
}
// createBlock assembles a new block at the given chain height.
func
createBlock
(
i
int
,
parent
,
hash
common
.
Hash
)
*
types
.
Block
{
func
createBlock
(
i
int
,
parent
,
hash
common
.
Hash
)
*
types
.
Block
{
header
:=
&
types
.
Header
{
Number
:
big
.
NewInt
(
int64
(
i
))}
header
:=
&
types
.
Header
{
Number
:
big
.
NewInt
(
int64
(
i
))}
block
:=
types
.
NewBlockWithHeader
(
header
)
block
:=
types
.
NewBlockWithHeader
(
header
)
...
@@ -39,6 +45,11 @@ func createBlock(i int, parent, hash common.Hash) *types.Block {
...
@@ -39,6 +45,11 @@ func createBlock(i int, parent, hash common.Hash) *types.Block {
return
block
return
block
}
}
// copyBlock makes a deep copy of a block suitable for local modifications.
func
copyBlock
(
block
*
types
.
Block
)
*
types
.
Block
{
return
createBlock
(
int
(
block
.
Number
()
.
Int64
()),
block
.
ParentHeaderHash
,
block
.
HeaderHash
)
}
func
createBlocksFromHashes
(
hashes
[]
common
.
Hash
)
map
[
common
.
Hash
]
*
types
.
Block
{
func
createBlocksFromHashes
(
hashes
[]
common
.
Hash
)
map
[
common
.
Hash
]
*
types
.
Block
{
blocks
:=
make
(
map
[
common
.
Hash
]
*
types
.
Block
)
blocks
:=
make
(
map
[
common
.
Hash
]
*
types
.
Block
)
for
i
:=
0
;
i
<
len
(
hashes
);
i
++
{
for
i
:=
0
;
i
<
len
(
hashes
);
i
++
{
...
@@ -76,10 +87,15 @@ func newTester() *downloadTester {
...
@@ -76,10 +87,15 @@ func newTester() *downloadTester {
return
tester
return
tester
}
}
// sync starts synchronizing with a remote peer, blocking until it completes.
func
(
dl
*
downloadTester
)
sync
(
id
string
)
error
{
return
dl
.
downloader
.
synchronise
(
id
,
dl
.
peerHashes
[
id
][
0
])
}
// syncTake is starts synchronising with a remote peer, but concurrently it also
// syncTake is starts synchronising with a remote peer, but concurrently it also
// starts fetching blocks that the downloader retrieved. IT blocks until both go
// starts fetching blocks that the downloader retrieved. IT blocks until both go
// routines terminate.
// routines terminate.
func
(
dl
*
downloadTester
)
syncTake
(
peerId
string
,
head
common
.
Hash
)
([]
*
Block
,
error
)
{
func
(
dl
*
downloadTester
)
syncTake
(
id
string
)
([]
*
Block
,
error
)
{
// Start a block collector to take blocks as they become available
// Start a block collector to take blocks as they become available
done
:=
make
(
chan
struct
{})
done
:=
make
(
chan
struct
{})
took
:=
[]
*
Block
{}
took
:=
[]
*
Block
{}
...
@@ -102,7 +118,7 @@ func (dl *downloadTester) syncTake(peerId string, head common.Hash) ([]*Block, e
...
@@ -102,7 +118,7 @@ func (dl *downloadTester) syncTake(peerId string, head common.Hash) ([]*Block, e
done
<-
struct
{}{}
done
<-
struct
{}{}
}()
}()
// Start the downloading, sync the taker and return
// Start the downloading, sync the taker and return
err
:=
dl
.
downloader
.
synchronise
(
peerId
,
hea
d
)
err
:=
dl
.
sync
(
i
d
)
done
<-
struct
{}{}
done
<-
struct
{}{}
<-
done
<-
done
...
@@ -124,9 +140,14 @@ func (dl *downloadTester) getBlock(hash common.Hash) *types.Block {
...
@@ -124,9 +140,14 @@ func (dl *downloadTester) getBlock(hash common.Hash) *types.Block {
func
(
dl
*
downloadTester
)
newPeer
(
id
string
,
hashes
[]
common
.
Hash
,
blocks
map
[
common
.
Hash
]
*
types
.
Block
)
error
{
func
(
dl
*
downloadTester
)
newPeer
(
id
string
,
hashes
[]
common
.
Hash
,
blocks
map
[
common
.
Hash
]
*
types
.
Block
)
error
{
err
:=
dl
.
downloader
.
RegisterPeer
(
id
,
hashes
[
0
],
dl
.
peerGetHashesFn
(
id
),
dl
.
peerGetBlocksFn
(
id
))
err
:=
dl
.
downloader
.
RegisterPeer
(
id
,
hashes
[
0
],
dl
.
peerGetHashesFn
(
id
),
dl
.
peerGetBlocksFn
(
id
))
if
err
==
nil
{
if
err
==
nil
{
// Assign the owned hashes and blocks to the peer
// Assign the owned hashes and blocks to the peer (deep copy)
dl
.
peerHashes
[
id
]
=
hashes
dl
.
peerHashes
[
id
]
=
make
([]
common
.
Hash
,
len
(
hashes
))
dl
.
peerBlocks
[
id
]
=
blocks
copy
(
dl
.
peerHashes
[
id
],
hashes
)
dl
.
peerBlocks
[
id
]
=
make
(
map
[
common
.
Hash
]
*
types
.
Block
)
for
hash
,
block
:=
range
blocks
{
dl
.
peerBlocks
[
id
][
hash
]
=
copyBlock
(
block
)
}
}
}
return
err
return
err
}
}
...
@@ -192,14 +213,14 @@ func (dl *downloadTester) peerGetBlocksFn(id string) func([]common.Hash) error {
...
@@ -192,14 +213,14 @@ func (dl *downloadTester) peerGetBlocksFn(id string) func([]common.Hash) error {
func
TestSynchronisation
(
t
*
testing
.
T
)
{
func
TestSynchronisation
(
t
*
testing
.
T
)
{
// Create a small enough block chain to download and the tester
// Create a small enough block chain to download and the tester
targetBlocks
:=
blockCacheLimit
-
15
targetBlocks
:=
blockCacheLimit
-
15
hashes
:=
createHashes
(
0
,
targetBlocks
)
hashes
:=
createHashes
(
targetBlocks
,
knownHash
)
blocks
:=
createBlocksFromHashes
(
hashes
)
blocks
:=
createBlocksFromHashes
(
hashes
)
tester
:=
newTester
()
tester
:=
newTester
()
tester
.
newPeer
(
"peer"
,
hashes
,
blocks
)
tester
.
newPeer
(
"peer"
,
hashes
,
blocks
)
// Synchronise with the peer and make sure all blocks were retrieved
// Synchronise with the peer and make sure all blocks were retrieved
if
err
:=
tester
.
downloader
.
synchronise
(
"peer"
,
hashes
[
0
]
);
err
!=
nil
{
if
err
:=
tester
.
sync
(
"peer"
);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
if
queued
:=
len
(
tester
.
downloader
.
queue
.
blockPool
);
queued
!=
targetBlocks
{
if
queued
:=
len
(
tester
.
downloader
.
queue
.
blockPool
);
queued
!=
targetBlocks
{
...
@@ -211,14 +232,14 @@ func TestSynchronisation(t *testing.T) {
...
@@ -211,14 +232,14 @@ func TestSynchronisation(t *testing.T) {
func
TestBlockTaking
(
t
*
testing
.
T
)
{
func
TestBlockTaking
(
t
*
testing
.
T
)
{
// Create a small enough block chain to download and the tester
// Create a small enough block chain to download and the tester
targetBlocks
:=
blockCacheLimit
-
15
targetBlocks
:=
blockCacheLimit
-
15
hashes
:=
createHashes
(
0
,
targetBlocks
)
hashes
:=
createHashes
(
targetBlocks
,
knownHash
)
blocks
:=
createBlocksFromHashes
(
hashes
)
blocks
:=
createBlocksFromHashes
(
hashes
)
tester
:=
newTester
()
tester
:=
newTester
()
tester
.
newPeer
(
"peer"
,
hashes
,
blocks
)
tester
.
newPeer
(
"peer"
,
hashes
,
blocks
)
// Synchronise with the peer and test block retrieval
// Synchronise with the peer and test block retrieval
if
err
:=
tester
.
downloader
.
synchronise
(
"peer"
,
hashes
[
0
]
);
err
!=
nil
{
if
err
:=
tester
.
sync
(
"peer"
);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
if
took
:=
tester
.
downloader
.
TakeBlocks
();
len
(
took
)
!=
targetBlocks
{
if
took
:=
tester
.
downloader
.
TakeBlocks
();
len
(
took
)
!=
targetBlocks
{
...
@@ -243,14 +264,14 @@ func TestInactiveDownloader(t *testing.T) {
...
@@ -243,14 +264,14 @@ func TestInactiveDownloader(t *testing.T) {
func
TestCancel
(
t
*
testing
.
T
)
{
func
TestCancel
(
t
*
testing
.
T
)
{
// Create a small enough block chain to download and the tester
// Create a small enough block chain to download and the tester
targetBlocks
:=
blockCacheLimit
-
15
targetBlocks
:=
blockCacheLimit
-
15
hashes
:=
createHashes
(
0
,
targetBlocks
)
hashes
:=
createHashes
(
targetBlocks
,
knownHash
)
blocks
:=
createBlocksFromHashes
(
hashes
)
blocks
:=
createBlocksFromHashes
(
hashes
)
tester
:=
newTester
()
tester
:=
newTester
()
tester
.
newPeer
(
"peer"
,
hashes
,
blocks
)
tester
.
newPeer
(
"peer"
,
hashes
,
blocks
)
// Synchronise with the peer, but cancel afterwards
// Synchronise with the peer, but cancel afterwards
if
err
:=
tester
.
downloader
.
synchronise
(
"peer"
,
hashes
[
0
]
);
err
!=
nil
{
if
err
:=
tester
.
sync
(
"peer"
);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
if
!
tester
.
downloader
.
Cancel
()
{
if
!
tester
.
downloader
.
Cancel
()
{
...
@@ -271,7 +292,7 @@ func TestCancel(t *testing.T) {
...
@@ -271,7 +292,7 @@ func TestCancel(t *testing.T) {
func
TestThrottling
(
t
*
testing
.
T
)
{
func
TestThrottling
(
t
*
testing
.
T
)
{
// Create a long block chain to download and the tester
// Create a long block chain to download and the tester
targetBlocks
:=
8
*
blockCacheLimit
targetBlocks
:=
8
*
blockCacheLimit
hashes
:=
createHashes
(
0
,
targetBlocks
)
hashes
:=
createHashes
(
targetBlocks
,
knownHash
)
blocks
:=
createBlocksFromHashes
(
hashes
)
blocks
:=
createBlocksFromHashes
(
hashes
)
tester
:=
newTester
()
tester
:=
newTester
()
...
@@ -280,7 +301,7 @@ func TestThrottling(t *testing.T) {
...
@@ -280,7 +301,7 @@ func TestThrottling(t *testing.T) {
// Start a synchronisation concurrently
// Start a synchronisation concurrently
errc
:=
make
(
chan
error
)
errc
:=
make
(
chan
error
)
go
func
()
{
go
func
()
{
errc
<-
tester
.
downloader
.
synchronise
(
"peer"
,
hashes
[
0
]
)
errc
<-
tester
.
sync
(
"peer"
)
}()
}()
// Iteratively take some blocks, always checking the retrieval count
// Iteratively take some blocks, always checking the retrieval count
for
total
:=
0
;
total
<
targetBlocks
;
{
for
total
:=
0
;
total
<
targetBlocks
;
{
...
@@ -309,17 +330,20 @@ func TestThrottling(t *testing.T) {
...
@@ -309,17 +330,20 @@ func TestThrottling(t *testing.T) {
// Tests that if a peer returns an invalid chain with a block pointing to a non-
// Tests that if a peer returns an invalid chain with a block pointing to a non-
// existing parent, it is correctly detected and handled.
// existing parent, it is correctly detected and handled.
func
TestNonExistingParentAttack
(
t
*
testing
.
T
)
{
func
TestNonExistingParentAttack
(
t
*
testing
.
T
)
{
tester
:=
newTester
()
// Forge a single-link chain with a forged header
// Forge a single-link chain with a forged header
hashes
:=
createHashes
(
0
,
1
)
hashes
:=
createHashes
(
1
,
knownHash
)
blocks
:=
createBlocksFromHashes
(
hashes
)
blocks
:=
createBlocksFromHashes
(
hashes
)
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
forged
:=
blocks
[
hashes
[
0
]]
hashes
=
createHashes
(
1
,
knownHash
)
forged
.
ParentHeaderHash
=
unknownHash
blocks
=
createBlocksFromHashes
(
hashes
)
blocks
[
hashes
[
0
]]
.
ParentHeaderHash
=
unknownHash
tester
.
newPeer
(
"attack"
,
hashes
,
blocks
)
// Try and sync with the malicious node and check that it fails
// Try and sync with the malicious node and check that it fails
tester
:=
newTester
()
if
err
:=
tester
.
sync
(
"attack"
);
err
!=
nil
{
tester
.
newPeer
(
"attack"
,
hashes
,
blocks
)
if
err
:=
tester
.
downloader
.
synchronise
(
"attack"
,
hashes
[
0
]);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
bs
:=
tester
.
downloader
.
TakeBlocks
()
bs
:=
tester
.
downloader
.
TakeBlocks
()
...
@@ -331,10 +355,8 @@ func TestNonExistingParentAttack(t *testing.T) {
...
@@ -331,10 +355,8 @@ func TestNonExistingParentAttack(t *testing.T) {
}
}
tester
.
downloader
.
Cancel
()
tester
.
downloader
.
Cancel
()
// Reconstruct a valid chain, and try to synchronize with it
// Try to synchronize with the valid chain and make sure it succeeds
forged
.
ParentHeaderHash
=
knownHash
if
err
:=
tester
.
sync
(
"valid"
);
err
!=
nil
{
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
if
err
:=
tester
.
downloader
.
synchronise
(
"valid"
,
hashes
[
0
]);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
bs
=
tester
.
downloader
.
TakeBlocks
()
bs
=
tester
.
downloader
.
TakeBlocks
()
...
@@ -348,21 +370,20 @@ func TestNonExistingParentAttack(t *testing.T) {
...
@@ -348,21 +370,20 @@ func TestNonExistingParentAttack(t *testing.T) {
// Tests that if a malicious peers keeps sending us repeating hashes, we don't
// Tests that if a malicious peers keeps sending us repeating hashes, we don't
// loop indefinitely.
// loop indefinitely.
func
TestRepeatingHashAttack
(
t
*
testing
.
T
)
{
func
TestRepeatingHashAttack
(
t
*
testing
.
T
)
{
// TODO: Is this thing valid??
tester
:=
newTester
()
// Create a valid chain, but drop the last link
// Create a valid chain, but drop the last link
hashes
:=
createHashes
(
0
,
blockCacheLimit
)
hashes
:=
createHashes
(
blockCacheLimit
,
knownHash
)
blocks
:=
createBlocksFromHashes
(
hashes
)
blocks
:=
createBlocksFromHashes
(
hashes
)
forged
:=
hashes
[
:
len
(
hashes
)
-
1
]
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
tester
.
newPeer
(
"attack"
,
hashes
[
:
len
(
hashes
)
-
1
],
blocks
)
// Try and sync with the malicious node
// Try and sync with the malicious node
tester
:=
newTester
()
tester
.
newPeer
(
"attack"
,
forged
,
blocks
)
errc
:=
make
(
chan
error
)
errc
:=
make
(
chan
error
)
go
func
()
{
go
func
()
{
errc
<-
tester
.
downloader
.
synchronise
(
"attack"
,
hashes
[
0
]
)
errc
<-
tester
.
sync
(
"attack"
)
}()
}()
// Make sure that syncing returns and does so with a failure
// Make sure that syncing returns and does so with a failure
select
{
select
{
case
<-
time
.
After
(
time
.
Second
)
:
case
<-
time
.
After
(
time
.
Second
)
:
...
@@ -373,8 +394,7 @@ func TestRepeatingHashAttack(t *testing.T) {
...
@@ -373,8 +394,7 @@ func TestRepeatingHashAttack(t *testing.T) {
}
}
}
}
// Ensure that a valid chain can still pass sync
// Ensure that a valid chain can still pass sync
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
if
err
:=
tester
.
sync
(
"valid"
);
err
!=
nil
{
if
err
:=
tester
.
downloader
.
synchronise
(
"valid"
,
hashes
[
0
]);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
}
}
...
@@ -382,23 +402,22 @@ func TestRepeatingHashAttack(t *testing.T) {
...
@@ -382,23 +402,22 @@ func TestRepeatingHashAttack(t *testing.T) {
// Tests that if a malicious peers returns a non-existent block hash, it should
// Tests that if a malicious peers returns a non-existent block hash, it should
// eventually time out and the sync reattempted.
// eventually time out and the sync reattempted.
func
TestNonExistingBlockAttack
(
t
*
testing
.
T
)
{
func
TestNonExistingBlockAttack
(
t
*
testing
.
T
)
{
tester
:=
newTester
()
// Create a valid chain, but forge the last link
// Create a valid chain, but forge the last link
hashes
:=
createHashes
(
0
,
blockCacheLimit
)
hashes
:=
createHashes
(
blockCacheLimit
,
knownHash
)
blocks
:=
createBlocksFromHashes
(
hashes
)
blocks
:=
createBlocksFromHashes
(
hashes
)
origin
:=
hashes
[
len
(
hashes
)
/
2
]
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
hashes
[
len
(
hashes
)
/
2
]
=
unknownHash
hashes
[
len
(
hashes
)
/
2
]
=
unknownHash
tester
.
newPeer
(
"attack"
,
hashes
,
blocks
)
// Try and sync with the malicious node and check that it fails
// Try and sync with the malicious node and check that it fails
tester
:=
newTester
()
if
err
:=
tester
.
sync
(
"attack"
);
err
!=
errPeersUnavailable
{
tester
.
newPeer
(
"attack"
,
hashes
,
blocks
)
if
err
:=
tester
.
downloader
.
synchronise
(
"attack"
,
hashes
[
0
]);
err
!=
errPeersUnavailable
{
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errPeersUnavailable
)
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errPeersUnavailable
)
}
}
// Ensure that a valid chain can still pass sync
// Ensure that a valid chain can still pass sync
hashes
[
len
(
hashes
)
/
2
]
=
origin
if
err
:=
tester
.
sync
(
"valid"
);
err
!=
nil
{
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
if
err
:=
tester
.
downloader
.
synchronise
(
"valid"
,
hashes
[
0
]);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
}
}
...
@@ -406,29 +425,28 @@ func TestNonExistingBlockAttack(t *testing.T) {
...
@@ -406,29 +425,28 @@ func TestNonExistingBlockAttack(t *testing.T) {
// Tests that if a malicious peer is returning hashes in a weird order, that the
// Tests that if a malicious peer is returning hashes in a weird order, that the
// sync throttler doesn't choke on them waiting for the valid blocks.
// sync throttler doesn't choke on them waiting for the valid blocks.
func
TestInvalidHashOrderAttack
(
t
*
testing
.
T
)
{
func
TestInvalidHashOrderAttack
(
t
*
testing
.
T
)
{
tester
:=
newTester
()
// Create a valid long chain, but reverse some hashes within
// Create a valid long chain, but reverse some hashes within
hashes
:=
createHashes
(
0
,
4
*
blockCacheLimit
)
hashes
:=
createHashes
(
4
*
blockCacheLimit
,
knownHash
)
blocks
:=
createBlocksFromHashes
(
hashes
)
blocks
:=
createBlocksFromHashes
(
hashes
)
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
chunk1
:=
make
([]
common
.
Hash
,
blockCacheLimit
)
chunk1
:=
make
([]
common
.
Hash
,
blockCacheLimit
)
chunk2
:=
make
([]
common
.
Hash
,
blockCacheLimit
)
chunk2
:=
make
([]
common
.
Hash
,
blockCacheLimit
)
copy
(
chunk1
,
hashes
[
blockCacheLimit
:
2
*
blockCacheLimit
])
copy
(
chunk1
,
hashes
[
blockCacheLimit
:
2
*
blockCacheLimit
])
copy
(
chunk2
,
hashes
[
2
*
blockCacheLimit
:
3
*
blockCacheLimit
])
copy
(
chunk2
,
hashes
[
2
*
blockCacheLimit
:
3
*
blockCacheLimit
])
reverse
:=
make
([]
common
.
Hash
,
len
(
hashes
))
copy
(
hashes
[
2
*
blockCacheLimit
:
],
chunk1
)
copy
(
reverse
,
hashes
)
copy
(
hashes
[
blockCacheLimit
:
],
chunk2
)
copy
(
reverse
[
2
*
blockCacheLimit
:
],
chunk1
)
tester
.
newPeer
(
"attack"
,
hashes
,
blocks
)
copy
(
reverse
[
blockCacheLimit
:
],
chunk2
)
// Try and sync with the malicious node and check that it fails
// Try and sync with the malicious node and check that it fails
tester
:=
newTester
()
if
_
,
err
:=
tester
.
syncTake
(
"attack"
);
err
!=
errInvalidChain
{
tester
.
newPeer
(
"attack"
,
reverse
,
blocks
)
if
_
,
err
:=
tester
.
syncTake
(
"attack"
,
reverse
[
0
]);
err
!=
errInvalidChain
{
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errInvalidChain
)
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errInvalidChain
)
}
}
// Ensure that a valid chain can still pass sync
// Ensure that a valid chain can still pass sync
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
if
_
,
err
:=
tester
.
syncTake
(
"valid"
);
err
!=
nil
{
if
_
,
err
:=
tester
.
syncTake
(
"valid"
,
hashes
[
0
]);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
}
}
...
@@ -436,18 +454,25 @@ func TestInvalidHashOrderAttack(t *testing.T) {
...
@@ -436,18 +454,25 @@ func TestInvalidHashOrderAttack(t *testing.T) {
// Tests that if a malicious peer makes up a random hash chain and tries to push
// Tests that if a malicious peer makes up a random hash chain and tries to push
// indefinitely, it actually gets caught with it.
// indefinitely, it actually gets caught with it.
func
TestMadeupHashChainAttack
(
t
*
testing
.
T
)
{
func
TestMadeupHashChainAttack
(
t
*
testing
.
T
)
{
tester
:=
newTester
()
blockSoftTTL
=
100
*
time
.
Millisecond
blockSoftTTL
=
100
*
time
.
Millisecond
crossCheckCycle
=
25
*
time
.
Millisecond
crossCheckCycle
=
25
*
time
.
Millisecond
// Create a long chain of hashes without backing blocks
// Create a long chain of hashes without backing blocks
hashes
:=
createHashes
(
0
,
1024
*
blockCacheLimit
)
hashes
:=
createHashes
(
4
*
blockCacheLimit
,
knownHash
)
blocks
:=
createBlocksFromHashes
(
hashes
)
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
tester
.
newPeer
(
"attack"
,
createHashes
(
1024
*
blockCacheLimit
,
knownHash
),
nil
)
// Try and sync with the malicious node and check that it fails
// Try and sync with the malicious node and check that it fails
tester
:=
newTester
()
if
_
,
err
:=
tester
.
syncTake
(
"attack"
);
err
!=
errCrossCheckFailed
{
tester
.
newPeer
(
"attack"
,
hashes
,
nil
)
if
_
,
err
:=
tester
.
syncTake
(
"attack"
,
hashes
[
0
]);
err
!=
errCrossCheckFailed
{
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errCrossCheckFailed
)
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errCrossCheckFailed
)
}
}
// Ensure that a valid chain can still pass sync
if
_
,
err
:=
tester
.
syncTake
(
"valid"
);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
}
// Tests that if a malicious peer makes up a random hash chain, and tries to push
// Tests that if a malicious peer makes up a random hash chain, and tries to push
...
@@ -456,13 +481,13 @@ func TestMadeupHashChainAttack(t *testing.T) {
...
@@ -456,13 +481,13 @@ func TestMadeupHashChainAttack(t *testing.T) {
// one by one prevents reliable block/parent verification.
// one by one prevents reliable block/parent verification.
func
TestMadeupHashChainDrippingAttack
(
t
*
testing
.
T
)
{
func
TestMadeupHashChainDrippingAttack
(
t
*
testing
.
T
)
{
// Create a random chain of hashes to drip
// Create a random chain of hashes to drip
hashes
:=
createHashes
(
0
,
16
*
blockCacheLimit
)
hashes
:=
createHashes
(
16
*
blockCacheLimit
,
knownHash
)
tester
:=
newTester
()
tester
:=
newTester
()
// Try and sync with the attacker, one hash at a time
// Try and sync with the attacker, one hash at a time
tester
.
maxHashFetch
=
1
tester
.
maxHashFetch
=
1
tester
.
newPeer
(
"attack"
,
hashes
,
nil
)
tester
.
newPeer
(
"attack"
,
hashes
,
nil
)
if
_
,
err
:=
tester
.
syncTake
(
"attack"
,
hashes
[
0
]
);
err
!=
errStallingPeer
{
if
_
,
err
:=
tester
.
syncTake
(
"attack"
);
err
!=
errStallingPeer
{
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errStallingPeer
)
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errStallingPeer
)
}
}
}
}
...
@@ -477,7 +502,7 @@ func TestMadeupBlockChainAttack(t *testing.T) {
...
@@ -477,7 +502,7 @@ func TestMadeupBlockChainAttack(t *testing.T) {
crossCheckCycle
=
25
*
time
.
Millisecond
crossCheckCycle
=
25
*
time
.
Millisecond
// Create a long chain of blocks and simulate an invalid chain by dropping every second
// Create a long chain of blocks and simulate an invalid chain by dropping every second
hashes
:=
createHashes
(
0
,
16
*
blockCacheLimit
)
hashes
:=
createHashes
(
16
*
blockCacheLimit
,
knownHash
)
blocks
:=
createBlocksFromHashes
(
hashes
)
blocks
:=
createBlocksFromHashes
(
hashes
)
gapped
:=
make
([]
common
.
Hash
,
len
(
hashes
)
/
2
)
gapped
:=
make
([]
common
.
Hash
,
len
(
hashes
)
/
2
)
...
@@ -487,7 +512,7 @@ func TestMadeupBlockChainAttack(t *testing.T) {
...
@@ -487,7 +512,7 @@ func TestMadeupBlockChainAttack(t *testing.T) {
// Try and sync with the malicious node and check that it fails
// Try and sync with the malicious node and check that it fails
tester
:=
newTester
()
tester
:=
newTester
()
tester
.
newPeer
(
"attack"
,
gapped
,
blocks
)
tester
.
newPeer
(
"attack"
,
gapped
,
blocks
)
if
_
,
err
:=
tester
.
syncTake
(
"attack"
,
gapped
[
0
]
);
err
!=
errCrossCheckFailed
{
if
_
,
err
:=
tester
.
syncTake
(
"attack"
);
err
!=
errCrossCheckFailed
{
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errCrossCheckFailed
)
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errCrossCheckFailed
)
}
}
// Ensure that a valid chain can still pass sync
// Ensure that a valid chain can still pass sync
...
@@ -495,7 +520,7 @@ func TestMadeupBlockChainAttack(t *testing.T) {
...
@@ -495,7 +520,7 @@ func TestMadeupBlockChainAttack(t *testing.T) {
crossCheckCycle
=
defaultCrossCheckCycle
crossCheckCycle
=
defaultCrossCheckCycle
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
if
_
,
err
:=
tester
.
syncTake
(
"valid"
,
hashes
[
0
]
);
err
!=
nil
{
if
_
,
err
:=
tester
.
syncTake
(
"valid"
);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
}
}
...
@@ -504,6 +529,8 @@ func TestMadeupBlockChainAttack(t *testing.T) {
...
@@ -504,6 +529,8 @@ func TestMadeupBlockChainAttack(t *testing.T) {
// attacker make up a valid hashes for random blocks, but also forges the block
// attacker make up a valid hashes for random blocks, but also forges the block
// parents to point to existing hashes.
// parents to point to existing hashes.
func
TestMadeupParentBlockChainAttack
(
t
*
testing
.
T
)
{
func
TestMadeupParentBlockChainAttack
(
t
*
testing
.
T
)
{
tester
:=
newTester
()
defaultBlockTTL
:=
blockSoftTTL
defaultBlockTTL
:=
blockSoftTTL
defaultCrossCheckCycle
:=
crossCheckCycle
defaultCrossCheckCycle
:=
crossCheckCycle
...
@@ -511,24 +538,24 @@ func TestMadeupParentBlockChainAttack(t *testing.T) {
...
@@ -511,24 +538,24 @@ func TestMadeupParentBlockChainAttack(t *testing.T) {
crossCheckCycle
=
25
*
time
.
Millisecond
crossCheckCycle
=
25
*
time
.
Millisecond
// Create a long chain of blocks and simulate an invalid chain by dropping every second
// Create a long chain of blocks and simulate an invalid chain by dropping every second
hashes
:=
createHashes
(
0
,
16
*
blockCacheLimit
)
hashes
:=
createHashes
(
16
*
blockCacheLimit
,
knownHash
)
blocks
:=
createBlocksFromHashes
(
hashes
)
blocks
:=
createBlocksFromHashes
(
hashes
)
forges
:=
createBlocksFromHashes
(
hashes
)
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
for
hash
,
block
:=
range
forges
{
block
.
ParentHeaderHash
=
hash
// Simulate pointing to already known hash
for
_
,
block
:=
range
blocks
{
block
.
ParentHeaderHash
=
knownHash
// Simulate pointing to already known hash
}
}
tester
.
newPeer
(
"attack"
,
hashes
,
blocks
)
// Try and sync with the malicious node and check that it fails
// Try and sync with the malicious node and check that it fails
tester
:=
newTester
()
if
_
,
err
:=
tester
.
syncTake
(
"attack"
);
err
!=
errCrossCheckFailed
{
tester
.
newPeer
(
"attack"
,
hashes
,
forges
)
if
_
,
err
:=
tester
.
syncTake
(
"attack"
,
hashes
[
0
]);
err
!=
errCrossCheckFailed
{
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errCrossCheckFailed
)
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errCrossCheckFailed
)
}
}
// Ensure that a valid chain can still pass sync
// Ensure that a valid chain can still pass sync
blockSoftTTL
=
defaultBlockTTL
blockSoftTTL
=
defaultBlockTTL
crossCheckCycle
=
defaultCrossCheckCycle
crossCheckCycle
=
defaultCrossCheckCycle
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
if
_
,
err
:=
tester
.
syncTake
(
"valid"
);
err
!=
nil
{
if
_
,
err
:=
tester
.
syncTake
(
"valid"
,
hashes
[
0
]);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
}
}
...
@@ -537,22 +564,25 @@ func TestMadeupParentBlockChainAttack(t *testing.T) {
...
@@ -537,22 +564,25 @@ func TestMadeupParentBlockChainAttack(t *testing.T) {
// the downloader, it will not keep refetching the same chain indefinitely, but
// the downloader, it will not keep refetching the same chain indefinitely, but
// gradually block pieces of it, until it's head is also blocked.
// gradually block pieces of it, until it's head is also blocked.
func
TestBannedChainStarvationAttack
(
t
*
testing
.
T
)
{
func
TestBannedChainStarvationAttack
(
t
*
testing
.
T
)
{
// Construct a valid chain, but ban one of the hashes in it
hashes
:=
createHashes
(
0
,
8
*
blockCacheLimit
)
hashes
[
len
(
hashes
)
/
2
+
23
]
=
bannedHash
// weird index to have non multiple of ban chunk size
blocks
:=
createBlocksFromHashes
(
hashes
)
// Create the tester and ban the selected hash
// Create the tester and ban the selected hash
tester
:=
newTester
()
tester
:=
newTester
()
tester
.
downloader
.
banned
.
Add
(
bannedHash
)
tester
.
downloader
.
banned
.
Add
(
bannedHash
)
// Construct a valid chain, for it and ban the fork
hashes
:=
createHashes
(
8
*
blockCacheLimit
,
knownHash
)
blocks
:=
createBlocksFromHashes
(
hashes
)
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
fork
:=
len
(
hashes
)
/
2
-
23
hashes
=
append
(
createHashes
(
4
*
blockCacheLimit
,
bannedHash
),
hashes
[
fork
:
]
...
)
blocks
=
createBlocksFromHashes
(
hashes
)
tester
.
newPeer
(
"attack"
,
hashes
,
blocks
)
// Iteratively try to sync, and verify that the banned hash list grows until
// Iteratively try to sync, and verify that the banned hash list grows until
// the head of the invalid chain is blocked too.
// the head of the invalid chain is blocked too.
tester
.
newPeer
(
"attack"
,
hashes
,
blocks
)
for
banned
:=
tester
.
downloader
.
banned
.
Size
();
;
{
for
banned
:=
tester
.
downloader
.
banned
.
Size
();
;
{
// Try to sync with the attacker, check hash chain failure
// Try to sync with the attacker, check hash chain failure
if
_
,
err
:=
tester
.
syncTake
(
"attack"
,
hashes
[
0
]
);
err
!=
errInvalidChain
{
if
_
,
err
:=
tester
.
syncTake
(
"attack"
);
err
!=
errInvalidChain
{
if
tester
.
downloader
.
banned
.
Has
(
hashes
[
0
])
&&
err
==
errBannedHead
{
if
tester
.
downloader
.
banned
.
Has
(
hashes
[
0
])
&&
err
==
errBannedHead
{
break
break
}
}
...
@@ -569,35 +599,45 @@ func TestBannedChainStarvationAttack(t *testing.T) {
...
@@ -569,35 +599,45 @@ func TestBannedChainStarvationAttack(t *testing.T) {
if
err
:=
tester
.
newPeer
(
"new attacker"
,
hashes
,
blocks
);
err
!=
errBannedHead
{
if
err
:=
tester
.
newPeer
(
"new attacker"
,
hashes
,
blocks
);
err
!=
errBannedHead
{
t
.
Fatalf
(
"peer registration mismatch: have %v, want %v"
,
err
,
errBannedHead
)
t
.
Fatalf
(
"peer registration mismatch: have %v, want %v"
,
err
,
errBannedHead
)
}
}
if
peer
:=
tester
.
downloader
.
peers
.
Peer
(
"ne
t
attacker"
);
peer
!=
nil
{
if
peer
:=
tester
.
downloader
.
peers
.
Peer
(
"ne
w
attacker"
);
peer
!=
nil
{
t
.
Fatalf
(
"banned attacker registered: %v"
,
peer
)
t
.
Fatalf
(
"banned attacker registered: %v"
,
peer
)
}
}
// Ensure that a valid chain can still pass sync
if
_
,
err
:=
tester
.
syncTake
(
"valid"
);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
}
// Tests that if a peer sends excessively many/large invalid chains that are
// Tests that if a peer sends excessively many/large invalid chains that are
// gradually banned, it will have an upper limit on the consumed memory and also
// gradually banned, it will have an upper limit on the consumed memory and also
// the origin bad hashes will not be evacuated.
// the origin bad hashes will not be evacuated.
func
TestBannedChainMemoryExhaustionAttack
(
t
*
testing
.
T
)
{
func
TestBannedChainMemoryExhaustionAttack
(
t
*
testing
.
T
)
{
// Create the tester and ban the selected hash
tester
:=
newTester
()
tester
.
downloader
.
banned
.
Add
(
bannedHash
)
// Reduce the test size a bit
// Reduce the test size a bit
defaultMaxBlockFetch
:=
MaxBlockFetch
defaultMaxBannedHashes
:=
maxBannedHashes
MaxBlockFetch
=
4
MaxBlockFetch
=
4
maxBannedHashes
=
256
maxBannedHashes
=
256
// Construct a banned chain with more chunks than the ban limit
// Construct a banned chain with more chunks than the ban limit
hashes
:=
createHashes
(
0
,
maxBannedHashes
*
MaxBlockFetch
)
hashes
:=
createHashes
(
8
*
blockCacheLimit
,
knownHash
)
hashes
[
len
(
hashes
)
-
1
]
=
bannedHash
// weird index to have non multiple of ban chunk size
blocks
:=
createBlocksFromHashes
(
hashes
)
blocks
:=
createBlocksFromHashes
(
hashes
)
tester
.
newPeer
(
"valid"
,
hashes
,
blocks
)
// Create the tester and ban the selected hash
fork
:=
len
(
hashes
)
/
2
-
23
tester
:=
newTester
()
hashes
=
append
(
createHashes
(
maxBannedHashes
*
MaxBlockFetch
,
bannedHash
),
hashes
[
fork
:
]
...
)
tester
.
downloader
.
banned
.
Add
(
bannedHash
)
blocks
=
createBlocksFromHashes
(
hashes
)
tester
.
newPeer
(
"attack"
,
hashes
,
blocks
)
// Iteratively try to sync, and verify that the banned hash list grows until
// Iteratively try to sync, and verify that the banned hash list grows until
// the head of the invalid chain is blocked too.
// the head of the invalid chain is blocked too.
tester
.
newPeer
(
"attack"
,
hashes
,
blocks
)
for
{
for
{
// Try to sync with the attacker, check hash chain failure
// Try to sync with the attacker, check hash chain failure
if
_
,
err
:=
tester
.
syncTake
(
"attack"
,
hashes
[
0
]
);
err
!=
errInvalidChain
{
if
_
,
err
:=
tester
.
syncTake
(
"attack"
);
err
!=
errInvalidChain
{
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errInvalidChain
)
t
.
Fatalf
(
"synchronisation error mismatch: have %v, want %v"
,
err
,
errInvalidChain
)
}
}
// Short circuit if the entire chain was banned
// Short circuit if the entire chain was banned
...
@@ -614,6 +654,13 @@ func TestBannedChainMemoryExhaustionAttack(t *testing.T) {
...
@@ -614,6 +654,13 @@ func TestBannedChainMemoryExhaustionAttack(t *testing.T) {
}
}
}
}
}
}
// Ensure that a valid chain can still pass sync
MaxBlockFetch
=
defaultMaxBlockFetch
maxBannedHashes
=
defaultMaxBannedHashes
if
_
,
err
:=
tester
.
syncTake
(
"valid"
);
err
!=
nil
{
t
.
Fatalf
(
"failed to synchronise blocks: %v"
,
err
)
}
}
}
// Tests that misbehaving peers are disconnected, whilst behaving ones are not.
// Tests that misbehaving peers are disconnected, whilst behaving ones are not.
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录