Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
whqwjb
go-ethereum
提交
5b0ee8ec
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,发现更多精彩内容 >>
提交
5b0ee8ec
编写于
10月 13, 2015
作者:
P
Péter Szilágyi
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
core, eth, trie: fix data races and merge/review issues
上级
aa0538db
变更
27
展开全部
隐藏空白更改
内联
并排
Showing
27 changed file
with
765 addition
and
465 deletion
+765
-465
core/block_processor.go
core/block_processor.go
+8
-6
core/blockchain.go
core/blockchain.go
+42
-29
core/blockchain_test.go
core/blockchain_test.go
+1
-1
core/chain_util.go
core/chain_util.go
+1
-1
core/chain_util_test.go
core/chain_util_test.go
+14
-14
core/state/sync.go
core/state/sync.go
+1
-2
core/state/sync_test.go
core/state/sync_test.go
+2
-2
core/types/receipt.go
core/types/receipt.go
+5
-5
core/vm/log.go
core/vm/log.go
+1
-1
eth/backend.go
eth/backend.go
+0
-1
eth/backend_test.go
eth/backend_test.go
+5
-5
eth/downloader/downloader.go
eth/downloader/downloader.go
+120
-71
eth/downloader/downloader_test.go
eth/downloader/downloader_test.go
+254
-210
eth/downloader/modes.go
eth/downloader/modes.go
+2
-2
eth/downloader/peer.go
eth/downloader/peer.go
+22
-6
eth/downloader/queue.go
eth/downloader/queue.go
+120
-58
eth/fetcher/fetcher.go
eth/fetcher/fetcher.go
+20
-6
eth/fetcher/fetcher_test.go
eth/fetcher/fetcher_test.go
+39
-10
eth/filters/filter_test.go
eth/filters/filter_test.go
+16
-17
eth/handler.go
eth/handler.go
+9
-8
eth/handler_test.go
eth/handler_test.go
+3
-1
eth/metrics.go
eth/metrics.go
+1
-1
eth/sync.go
eth/sync.go
+17
-1
eth/sync_test.go
eth/sync_test.go
+53
-0
ethdb/memory_database.go
ethdb/memory_database.go
+7
-3
rpc/api/eth.go
rpc/api/eth.go
+1
-3
trie/sync.go
trie/sync.go
+1
-1
未找到文件。
core/block_processor.go
浏览文件 @
5b0ee8ec
...
...
@@ -195,14 +195,16 @@ func (sm *BlockProcessor) Process(block *types.Block) (logs vm.Logs, receipts ty
defer
sm
.
mutex
.
Unlock
()
if
sm
.
bc
.
HasBlock
(
block
.
Hash
())
{
return
nil
,
nil
,
&
KnownBlockError
{
block
.
Number
(),
block
.
Hash
()}
if
_
,
err
:=
state
.
New
(
block
.
Root
(),
sm
.
chainDb
);
err
==
nil
{
return
nil
,
nil
,
&
KnownBlockError
{
block
.
Number
(),
block
.
Hash
()}
}
}
if
!
sm
.
bc
.
HasBlock
(
block
.
ParentHash
())
{
return
nil
,
nil
,
ParentError
(
block
.
ParentHash
())
if
parent
:=
sm
.
bc
.
GetBlock
(
block
.
ParentHash
());
parent
!=
nil
{
if
_
,
err
:=
state
.
New
(
parent
.
Root
(),
sm
.
chainDb
);
err
==
nil
{
return
sm
.
processWithParent
(
block
,
parent
)
}
}
parent
:=
sm
.
bc
.
GetBlock
(
block
.
ParentHash
())
return
sm
.
processWithParent
(
block
,
parent
)
return
nil
,
nil
,
ParentError
(
block
.
ParentHash
())
}
func
(
sm
*
BlockProcessor
)
processWithParent
(
block
,
parent
*
types
.
Block
)
(
logs
vm
.
Logs
,
receipts
types
.
Receipts
,
err
error
)
{
...
...
core/blockchain.go
浏览文件 @
5b0ee8ec
...
...
@@ -18,11 +18,13 @@
package
core
import
(
crand
"crypto/rand"
"errors"
"fmt"
"io"
"math"
"math/big"
"math/rand"
mrand
"math/rand"
"runtime"
"sync"
"sync/atomic"
...
...
@@ -89,7 +91,8 @@ type BlockChain struct {
procInterrupt
int32
// interrupt signaler for block processing
wg
sync
.
WaitGroup
pow
pow
.
PoW
pow
pow
.
PoW
rand
*
mrand
.
Rand
}
func
NewBlockChain
(
chainDb
ethdb
.
Database
,
pow
pow
.
PoW
,
mux
*
event
.
TypeMux
)
(
*
BlockChain
,
error
)
{
...
...
@@ -112,6 +115,12 @@ func NewBlockChain(chainDb ethdb.Database, pow pow.PoW, mux *event.TypeMux) (*Bl
futureBlocks
:
futureBlocks
,
pow
:
pow
,
}
// Seed a fast but crypto originating random generator
seed
,
err
:=
crand
.
Int
(
crand
.
Reader
,
big
.
NewInt
(
math
.
MaxInt64
))
if
err
!=
nil
{
return
nil
,
err
}
bc
.
rand
=
mrand
.
New
(
mrand
.
NewSource
(
seed
.
Int64
()))
bc
.
genesisBlock
=
bc
.
GetBlockByNumber
(
0
)
if
bc
.
genesisBlock
==
nil
{
...
...
@@ -178,21 +187,21 @@ func (self *BlockChain) loadLastState() error {
fastTd
:=
self
.
GetTd
(
self
.
currentFastBlock
.
Hash
())
glog
.
V
(
logger
.
Info
)
.
Infof
(
"Last header: #%d [%x…] TD=%v"
,
self
.
currentHeader
.
Number
,
self
.
currentHeader
.
Hash
()
.
Bytes
()[
:
4
],
headerTd
)
glog
.
V
(
logger
.
Info
)
.
Infof
(
"Fast block: #%d [%x…] TD=%v"
,
self
.
currentFastBlock
.
Number
(),
self
.
currentFastBlock
.
Hash
()
.
Bytes
()[
:
4
],
fastTd
)
glog
.
V
(
logger
.
Info
)
.
Infof
(
"Last block: #%d [%x…] TD=%v"
,
self
.
currentBlock
.
Number
(),
self
.
currentBlock
.
Hash
()
.
Bytes
()[
:
4
],
blockTd
)
glog
.
V
(
logger
.
Info
)
.
Infof
(
"Fast block: #%d [%x…] TD=%v"
,
self
.
currentFastBlock
.
Number
(),
self
.
currentFastBlock
.
Hash
()
.
Bytes
()[
:
4
],
fastTd
)
return
nil
}
// SetHead rewind
the local chain to a new head entity. In the case of headers,
//
everything above the new head will be deleted and the new one set. In the case
//
of blocks though, the head may be further rewound if block bodies are missing
//
(non-archive
nodes after a fast sync).
// SetHead rewind
s the local chain to a new head. In the case of headers, everything
//
above the new head will be deleted and the new one set. In the case of blocks
//
though, the head may be further rewound if block bodies are missing (non-archive
// nodes after a fast sync).
func
(
bc
*
BlockChain
)
SetHead
(
head
uint64
)
{
bc
.
mu
.
Lock
()
defer
bc
.
mu
.
Unlock
()
// Figure out the highest known canonical
assignment
// Figure out the highest known canonical
headers and/or blocks
height
:=
uint64
(
0
)
if
bc
.
currentHeader
!=
nil
{
if
hh
:=
bc
.
currentHeader
.
Number
.
Uint64
();
hh
>
height
{
...
...
@@ -266,7 +275,7 @@ func (bc *BlockChain) SetHead(head uint64) {
// FastSyncCommitHead sets the current head block to the one defined by the hash
// irrelevant what the chain contents were prior.
func
(
self
*
BlockChain
)
FastSyncCommitHead
(
hash
common
.
Hash
)
error
{
// Make sure that both the block as well at it
'
s state trie exists
// Make sure that both the block as well at its state trie exists
block
:=
self
.
GetBlock
(
hash
)
if
block
==
nil
{
return
fmt
.
Errorf
(
"non existent block [%x…]"
,
hash
[
:
4
])
...
...
@@ -298,7 +307,7 @@ func (self *BlockChain) LastBlockHash() common.Hash {
}
// CurrentHeader retrieves the current head header of the canonical chain. The
// header is retrieved from the
chain manager
's internal cache.
// header is retrieved from the
blockchain
's internal cache.
func
(
self
*
BlockChain
)
CurrentHeader
()
*
types
.
Header
{
self
.
mu
.
RLock
()
defer
self
.
mu
.
RUnlock
()
...
...
@@ -307,7 +316,7 @@ func (self *BlockChain) CurrentHeader() *types.Header {
}
// CurrentBlock retrieves the current head block of the canonical chain. The
// block is retrieved from the
chain manager
's internal cache.
// block is retrieved from the
blockchain
's internal cache.
func
(
self
*
BlockChain
)
CurrentBlock
()
*
types
.
Block
{
self
.
mu
.
RLock
()
defer
self
.
mu
.
RUnlock
()
...
...
@@ -316,7 +325,7 @@ func (self *BlockChain) CurrentBlock() *types.Block {
}
// CurrentFastBlock retrieves the current fast-sync head block of the canonical
// chain. The block is retrieved from the
chain manager
's internal cache.
// chain. The block is retrieved from the
blockchain
's internal cache.
func
(
self
*
BlockChain
)
CurrentFastBlock
()
*
types
.
Block
{
self
.
mu
.
RLock
()
defer
self
.
mu
.
RUnlock
()
...
...
@@ -353,7 +362,7 @@ func (bc *BlockChain) ResetWithGenesisBlock(genesis *types.Block) {
bc
.
mu
.
Lock
()
defer
bc
.
mu
.
Unlock
()
// Prepare the genesis block and reinitiali
z
e the chain
// Prepare the genesis block and reinitiali
s
e the chain
if
err
:=
WriteTd
(
bc
.
chainDb
,
genesis
.
Hash
(),
genesis
.
Difficulty
());
err
!=
nil
{
glog
.
Fatalf
(
"failed to write genesis block TD: %v"
,
err
)
}
...
...
@@ -403,7 +412,7 @@ func (self *BlockChain) ExportN(w io.Writer, first uint64, last uint64) error {
// insert injects a new head block into the current block chain. This method
// assumes that the block is indeed a true head. It will also reset the head
// header and the head fast sync block to this very same block to prevent them
// from
diverging on a different header chain
.
// from
pointing to a possibly old canonical chain (i.e. side chain by now)
.
//
// Note, this function assumes that the `mu` mutex is held!
func
(
bc
*
BlockChain
)
insert
(
block
*
types
.
Block
)
{
...
...
@@ -625,10 +634,10 @@ const (
// writeHeader writes a header into the local chain, given that its parent is
// already known. If the total difficulty of the newly inserted header becomes
// greater than the
old
known TD, the canonical chain is re-routed.
// greater than the
current
known TD, the canonical chain is re-routed.
//
// Note: This method is not concurrent-safe with inserting blocks simultaneously
// into the chain, as side effects caused by reorgani
z
ations cannot be emulated
// into the chain, as side effects caused by reorgani
s
ations cannot be emulated
// without the real blocks. Hence, writing headers directly should only be done
// in two scenarios: pure-header mode of operation (light clients), or properly
// separated header/block phases (non-archive clients).
...
...
@@ -678,10 +687,9 @@ func (self *BlockChain) writeHeader(header *types.Header) error {
return
nil
}
// InsertHeaderChain will attempt to insert the given header chain in to the
// local chain, possibly creating a fork. If an error is returned, it will
// return the index number of the failing header as well an error describing
// what went wrong.
// InsertHeaderChain attempts to insert the given header chain in to the local
// chain, possibly creating a reorg. If an error is returned, it will return the
// index number of the failing header as well an error describing what went wrong.
//
// The verify parameter can be used to fine tune whether nonce verification
// should be done or not. The reason behind the optional check is because some
...
...
@@ -702,7 +710,7 @@ func (self *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int)
// Generate the list of headers that should be POW verified
verify
:=
make
([]
bool
,
len
(
chain
))
for
i
:=
0
;
i
<
len
(
verify
)
/
checkFreq
;
i
++
{
index
:=
i
*
checkFreq
+
rand
.
Intn
(
checkFreq
)
index
:=
i
*
checkFreq
+
self
.
rand
.
Intn
(
checkFreq
)
if
index
>=
len
(
verify
)
{
index
=
len
(
verify
)
-
1
}
...
...
@@ -766,10 +774,6 @@ func (self *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int)
pending
.
Wait
()
// If anything failed, report
if
atomic
.
LoadInt32
(
&
self
.
procInterrupt
)
==
1
{
glog
.
V
(
logger
.
Debug
)
.
Infoln
(
"premature abort during receipt chain processing"
)
return
0
,
nil
}
if
failed
>
0
{
for
i
,
err
:=
range
errs
{
if
err
!=
nil
{
...
...
@@ -807,6 +811,9 @@ func (self *BlockChain) InsertHeaderChain(chain []*types.Header, checkFreq int)
// Rollback is designed to remove a chain of links from the database that aren't
// certain enough to be valid.
func
(
self
*
BlockChain
)
Rollback
(
chain
[]
common
.
Hash
)
{
self
.
mu
.
Lock
()
defer
self
.
mu
.
Unlock
()
for
i
:=
len
(
chain
)
-
1
;
i
>=
0
;
i
--
{
hash
:=
chain
[
i
]
...
...
@@ -905,6 +912,12 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
glog
.
Fatal
(
errs
[
index
])
return
}
if
err
:=
WriteMipmapBloom
(
self
.
chainDb
,
block
.
NumberU64
(),
receipts
);
err
!=
nil
{
errs
[
index
]
=
fmt
.
Errorf
(
"failed to write log blooms: %v"
,
err
)
atomic
.
AddInt32
(
&
failed
,
1
)
glog
.
Fatal
(
errs
[
index
])
return
}
atomic
.
AddInt32
(
&
stats
.
processed
,
1
)
}
}
...
...
@@ -920,10 +933,6 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
pending
.
Wait
()
// If anything failed, report
if
atomic
.
LoadInt32
(
&
self
.
procInterrupt
)
==
1
{
glog
.
V
(
logger
.
Debug
)
.
Infoln
(
"premature abort during receipt chain processing"
)
return
0
,
nil
}
if
failed
>
0
{
for
i
,
err
:=
range
errs
{
if
err
!=
nil
{
...
...
@@ -931,6 +940,10 @@ func (self *BlockChain) InsertReceiptChain(blockChain types.Blocks, receiptChain
}
}
}
if
atomic
.
LoadInt32
(
&
self
.
procInterrupt
)
==
1
{
glog
.
V
(
logger
.
Debug
)
.
Infoln
(
"premature abort during receipt chain processing"
)
return
0
,
nil
}
// Update the head fast sync block if better
self
.
mu
.
Lock
()
head
:=
blockChain
[
len
(
errs
)
-
1
]
...
...
core/blockchain_test.go
浏览文件 @
5b0ee8ec
...
...
@@ -452,7 +452,7 @@ func makeBlockChainWithDiff(genesis *types.Block, d []int, seed byte) []*types.B
func
chm
(
genesis
*
types
.
Block
,
db
ethdb
.
Database
)
*
BlockChain
{
var
eventMux
event
.
TypeMux
bc
:=
&
BlockChain
{
chainDb
:
db
,
genesisBlock
:
genesis
,
eventMux
:
&
eventMux
,
pow
:
FakePow
{}}
bc
:=
&
BlockChain
{
chainDb
:
db
,
genesisBlock
:
genesis
,
eventMux
:
&
eventMux
,
pow
:
FakePow
{}
,
rand
:
rand
.
New
(
rand
.
NewSource
(
0
))
}
bc
.
headerCache
,
_
=
lru
.
New
(
100
)
bc
.
bodyCache
,
_
=
lru
.
New
(
100
)
bc
.
bodyRLPCache
,
_
=
lru
.
New
(
100
)
...
...
core/chain_util.go
浏览文件 @
5b0ee8ec
...
...
@@ -394,7 +394,7 @@ func WriteMipmapBloom(db ethdb.Database, number uint64, receipts types.Receipts)
bloomDat
,
_
:=
db
.
Get
(
key
)
bloom
:=
types
.
BytesToBloom
(
bloomDat
)
for
_
,
receipt
:=
range
receipts
{
for
_
,
log
:=
range
receipt
.
Logs
()
{
for
_
,
log
:=
range
receipt
.
Logs
{
bloom
.
Add
(
log
.
Address
.
Big
())
}
}
...
...
core/chain_util_test.go
浏览文件 @
5b0ee8ec
...
...
@@ -345,15 +345,15 @@ func TestMipmapBloom(t *testing.T) {
db
,
_
:=
ethdb
.
NewMemDatabase
()
receipt1
:=
new
(
types
.
Receipt
)
receipt1
.
SetLogs
(
vm
.
Logs
{
receipt1
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
common
.
BytesToAddress
([]
byte
(
"test"
))},
&
vm
.
Log
{
Address
:
common
.
BytesToAddress
([]
byte
(
"address"
))},
}
)
}
receipt2
:=
new
(
types
.
Receipt
)
receipt2
.
SetLogs
(
vm
.
Logs
{
receipt2
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
common
.
BytesToAddress
([]
byte
(
"test"
))},
&
vm
.
Log
{
Address
:
common
.
BytesToAddress
([]
byte
(
"address1"
))},
}
)
}
WriteMipmapBloom
(
db
,
1
,
types
.
Receipts
{
receipt1
})
WriteMipmapBloom
(
db
,
2
,
types
.
Receipts
{
receipt2
})
...
...
@@ -368,15 +368,15 @@ func TestMipmapBloom(t *testing.T) {
// reset
db
,
_
=
ethdb
.
NewMemDatabase
()
receipt
:=
new
(
types
.
Receipt
)
receipt
.
SetLogs
(
vm
.
Logs
{
receipt
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
common
.
BytesToAddress
([]
byte
(
"test"
))},
}
)
}
WriteMipmapBloom
(
db
,
999
,
types
.
Receipts
{
receipt1
})
receipt
=
new
(
types
.
Receipt
)
receipt
.
SetLogs
(
vm
.
Logs
{
receipt
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
common
.
BytesToAddress
([]
byte
(
"test 1"
))},
}
)
}
WriteMipmapBloom
(
db
,
1000
,
types
.
Receipts
{
receipt
})
bloom
:=
GetMipmapBloom
(
db
,
1000
,
1000
)
...
...
@@ -403,22 +403,22 @@ func TestMipmapChain(t *testing.T) {
defer
db
.
Close
()
genesis
:=
WriteGenesisBlockForTesting
(
db
,
GenesisAccount
{
addr
,
big
.
NewInt
(
1000000
)})
chain
:=
GenerateChain
(
genesis
,
db
,
1010
,
func
(
i
int
,
gen
*
BlockGen
)
{
chain
,
receipts
:=
GenerateChain
(
genesis
,
db
,
1010
,
func
(
i
int
,
gen
*
BlockGen
)
{
var
receipts
types
.
Receipts
switch
i
{
case
1
:
receipt
:=
types
.
NewReceipt
(
nil
,
new
(
big
.
Int
))
receipt
.
SetLogs
(
vm
.
Logs
{
receipt
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
addr
,
Topics
:
[]
common
.
Hash
{
hash1
},
},
}
)
}
gen
.
AddUncheckedReceipt
(
receipt
)
receipts
=
types
.
Receipts
{
receipt
}
case
1000
:
receipt
:=
types
.
NewReceipt
(
nil
,
new
(
big
.
Int
))
receipt
.
SetLogs
(
vm
.
Logs
{
&
vm
.
Log
{
Address
:
addr2
}})
receipt
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
addr2
}}
gen
.
AddUncheckedReceipt
(
receipt
)
receipts
=
types
.
Receipts
{
receipt
}
...
...
@@ -431,7 +431,7 @@ func TestMipmapChain(t *testing.T) {
}
WriteMipmapBloom
(
db
,
uint64
(
i
+
1
),
receipts
)
})
for
_
,
block
:=
range
chain
{
for
i
,
block
:=
range
chain
{
WriteBlock
(
db
,
block
)
if
err
:=
WriteCanonicalHash
(
db
,
block
.
Hash
(),
block
.
NumberU64
());
err
!=
nil
{
t
.
Fatalf
(
"failed to insert block number: %v"
,
err
)
...
...
@@ -439,7 +439,7 @@ func TestMipmapChain(t *testing.T) {
if
err
:=
WriteHeadBlockHash
(
db
,
block
.
Hash
());
err
!=
nil
{
t
.
Fatalf
(
"failed to insert block number: %v"
,
err
)
}
if
err
:=
PutBlockReceipts
(
db
,
block
,
block
.
Receipts
()
);
err
!=
nil
{
if
err
:=
PutBlockReceipts
(
db
,
block
.
Hash
(),
receipts
[
i
]
);
err
!=
nil
{
t
.
Fatal
(
"error writing block receipts:"
,
err
)
}
}
...
...
core/state/sync.go
浏览文件 @
5b0ee8ec
...
...
@@ -26,14 +26,13 @@ import (
"github.com/ethereum/go-ethereum/trie"
)
// StateSync is the main state
synchronisation scheduler, which provides yet the
// StateSync is the main state synchronisation scheduler, which provides yet the
// unknown state hashes to retrieve, accepts node data associated with said hashes
// and reconstructs the state database step by step until all is done.
type
StateSync
trie
.
TrieSync
// NewStateSync create a new state trie download scheduler.
func
NewStateSync
(
root
common
.
Hash
,
database
ethdb
.
Database
)
*
StateSync
{
// Pre-declare the result syncer t
var
syncer
*
trie
.
TrieSync
callback
:=
func
(
leaf
[]
byte
,
parent
common
.
Hash
)
error
{
...
...
core/state/sync_test.go
浏览文件 @
5b0ee8ec
...
...
@@ -38,7 +38,7 @@ type testAccount struct {
func
makeTestState
()
(
ethdb
.
Database
,
common
.
Hash
,
[]
*
testAccount
)
{
// Create an empty state
db
,
_
:=
ethdb
.
NewMemDatabase
()
state
:=
New
(
common
.
Hash
{},
db
)
state
,
_
:=
New
(
common
.
Hash
{},
db
)
// Fill it with some arbitrary data
accounts
:=
[]
*
testAccount
{}
...
...
@@ -68,7 +68,7 @@ func makeTestState() (ethdb.Database, common.Hash, []*testAccount) {
// checkStateAccounts cross references a reconstructed state with an expected
// account array.
func
checkStateAccounts
(
t
*
testing
.
T
,
db
ethdb
.
Database
,
root
common
.
Hash
,
accounts
[]
*
testAccount
)
{
state
:=
New
(
root
,
db
)
state
,
_
:=
New
(
root
,
db
)
for
i
,
acc
:=
range
accounts
{
if
balance
:=
state
.
GetBalance
(
acc
.
address
);
balance
.
Cmp
(
acc
.
balance
)
!=
0
{
...
...
core/types/receipt.go
浏览文件 @
5b0ee8ec
...
...
@@ -67,7 +67,7 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
return
nil
}
// RlpEncode implements common.RlpEncode required for SHA derivation.
// RlpEncode implements common.RlpEncode required for SHA
3
derivation.
func
(
r
*
Receipt
)
RlpEncode
()
[]
byte
{
bytes
,
err
:=
rlp
.
EncodeToBytes
(
r
)
if
err
!=
nil
{
...
...
@@ -82,7 +82,7 @@ func (r *Receipt) String() string {
}
// ReceiptForStorage is a wrapper around a Receipt that flattens and parses the
// entire content of a receipt, opposed to only the consensus fields originally.
// entire content of a receipt,
as
opposed to only the consensus fields originally.
type
ReceiptForStorage
Receipt
// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
...
...
@@ -95,8 +95,8 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
return
rlp
.
Encode
(
w
,
[]
interface
{}{
r
.
PostState
,
r
.
CumulativeGasUsed
,
r
.
Bloom
,
r
.
TxHash
,
r
.
ContractAddress
,
logs
,
r
.
GasUsed
})
}
// DecodeRLP implements rlp.Decoder, and loads
the consensus fields of a receipt
// from an RLP stream.
// DecodeRLP implements rlp.Decoder, and loads
both consensus and implementation
// f
ields of a receipt f
rom an RLP stream.
func
(
r
*
ReceiptForStorage
)
DecodeRLP
(
s
*
rlp
.
Stream
)
error
{
var
receipt
struct
{
PostState
[]
byte
...
...
@@ -125,7 +125,7 @@ func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
// Receipts is a wrapper around a Receipt array to implement types.DerivableList.
type
Receipts
[]
*
Receipt
// RlpEncode implements common.RlpEncode required for SHA derivation.
// RlpEncode implements common.RlpEncode required for SHA
3
derivation.
func
(
r
Receipts
)
RlpEncode
()
[]
byte
{
bytes
,
err
:=
rlp
.
EncodeToBytes
(
r
)
if
err
!=
nil
{
...
...
core/vm/log.go
浏览文件 @
5b0ee8ec
...
...
@@ -66,6 +66,6 @@ func (l *Log) String() string {
type
Logs
[]
*
Log
// LogForStorage is a wrapper around a Log that flattens and parses the entire
// content of a log, opposed to only the consensus fields originally (by hiding
// content of a log,
as
opposed to only the consensus fields originally (by hiding
// the rlp interface methods).
type
LogForStorage
Log
eth/backend.go
浏览文件 @
5b0ee8ec
...
...
@@ -391,7 +391,6 @@ func New(config *Config) (*Ethereum, error) {
if
err
==
core
.
ErrNoGenesis
{
return
nil
,
fmt
.
Errorf
(
`Genesis block not found. Please supply a genesis block with the "--genesis /path/to/file" argument`
)
}
return
nil
,
err
}
newPool
:=
core
.
NewTxPool
(
eth
.
EventMux
(),
eth
.
blockchain
.
State
,
eth
.
blockchain
.
GasLimit
)
...
...
eth/backend_test.go
浏览文件 @
5b0ee8ec
...
...
@@ -16,17 +16,17 @@ func TestMipmapUpgrade(t *testing.T) {
addr
:=
common
.
BytesToAddress
([]
byte
(
"jeff"
))
genesis
:=
core
.
WriteGenesisBlockForTesting
(
db
)
chain
:=
core
.
GenerateChain
(
genesis
,
db
,
10
,
func
(
i
int
,
gen
*
core
.
BlockGen
)
{
chain
,
receipts
:=
core
.
GenerateChain
(
genesis
,
db
,
10
,
func
(
i
int
,
gen
*
core
.
BlockGen
)
{
var
receipts
types
.
Receipts
switch
i
{
case
1
:
receipt
:=
types
.
NewReceipt
(
nil
,
new
(
big
.
Int
))
receipt
.
SetLogs
(
vm
.
Logs
{
&
vm
.
Log
{
Address
:
addr
}})
receipt
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
addr
}}
gen
.
AddUncheckedReceipt
(
receipt
)
receipts
=
types
.
Receipts
{
receipt
}
case
2
:
receipt
:=
types
.
NewReceipt
(
nil
,
new
(
big
.
Int
))
receipt
.
SetLogs
(
vm
.
Logs
{
&
vm
.
Log
{
Address
:
addr
}})
receipt
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
addr
}}
gen
.
AddUncheckedReceipt
(
receipt
)
receipts
=
types
.
Receipts
{
receipt
}
}
...
...
@@ -37,7 +37,7 @@ func TestMipmapUpgrade(t *testing.T) {
t
.
Fatal
(
err
)
}
})
for
_
,
block
:=
range
chain
{
for
i
,
block
:=
range
chain
{
core
.
WriteBlock
(
db
,
block
)
if
err
:=
core
.
WriteCanonicalHash
(
db
,
block
.
Hash
(),
block
.
NumberU64
());
err
!=
nil
{
t
.
Fatalf
(
"failed to insert block number: %v"
,
err
)
...
...
@@ -45,7 +45,7 @@ func TestMipmapUpgrade(t *testing.T) {
if
err
:=
core
.
WriteHeadBlockHash
(
db
,
block
.
Hash
());
err
!=
nil
{
t
.
Fatalf
(
"failed to insert block number: %v"
,
err
)
}
if
err
:=
core
.
PutBlockReceipts
(
db
,
block
,
block
.
Receipts
()
);
err
!=
nil
{
if
err
:=
core
.
PutBlockReceipts
(
db
,
block
.
Hash
(),
receipts
[
i
]
);
err
!=
nil
{
t
.
Fatal
(
"error writing block receipts:"
,
err
)
}
}
...
...
eth/downloader/downloader.go
浏览文件 @
5b0ee8ec
此差异已折叠。
点击以展开。
eth/downloader/downloader_test.go
浏览文件 @
5b0ee8ec
此差异已折叠。
点击以展开。
eth/downloader/modes.go
浏览文件 @
5b0ee8ec
...
...
@@ -20,7 +20,7 @@ package downloader
type
SyncMode
int
const
(
FullSync
SyncMode
=
iota
// Synchronise the entire block
-
chain history from full blocks
FastSync
// Qui
kc
ly download the headers, full sync only at the chain head
FullSync
SyncMode
=
iota
// Synchronise the entire blockchain history from full blocks
FastSync
// Qui
ck
ly download the headers, full sync only at the chain head
LightSync
// Download only the headers and terminate afterwards
)
eth/downloader/peer.go
浏览文件 @
5b0ee8ec
...
...
@@ -124,6 +124,10 @@ func (p *peer) Reset() {
// Fetch61 sends a block retrieval request to the remote peer.
func
(
p
*
peer
)
Fetch61
(
request
*
fetchRequest
)
error
{
// Sanity check the protocol version
if
p
.
version
!=
61
{
panic
(
fmt
.
Sprintf
(
"block fetch [eth/61] requested on eth/%d"
,
p
.
version
))
}
// Short circuit if the peer is already fetching
if
!
atomic
.
CompareAndSwapInt32
(
&
p
.
blockIdle
,
0
,
1
)
{
return
errAlreadyFetching
...
...
@@ -142,6 +146,10 @@ func (p *peer) Fetch61(request *fetchRequest) error {
// FetchBodies sends a block body retrieval request to the remote peer.
func
(
p
*
peer
)
FetchBodies
(
request
*
fetchRequest
)
error
{
// Sanity check the protocol version
if
p
.
version
<
62
{
panic
(
fmt
.
Sprintf
(
"body fetch [eth/62+] requested on eth/%d"
,
p
.
version
))
}
// Short circuit if the peer is already fetching
if
!
atomic
.
CompareAndSwapInt32
(
&
p
.
blockIdle
,
0
,
1
)
{
return
errAlreadyFetching
...
...
@@ -160,6 +168,10 @@ func (p *peer) FetchBodies(request *fetchRequest) error {
// FetchReceipts sends a receipt retrieval request to the remote peer.
func
(
p
*
peer
)
FetchReceipts
(
request
*
fetchRequest
)
error
{
// Sanity check the protocol version
if
p
.
version
<
63
{
panic
(
fmt
.
Sprintf
(
"body fetch [eth/63+] requested on eth/%d"
,
p
.
version
))
}
// Short circuit if the peer is already fetching
if
!
atomic
.
CompareAndSwapInt32
(
&
p
.
receiptIdle
,
0
,
1
)
{
return
errAlreadyFetching
...
...
@@ -178,6 +190,10 @@ func (p *peer) FetchReceipts(request *fetchRequest) error {
// FetchNodeData sends a node state data retrieval request to the remote peer.
func
(
p
*
peer
)
FetchNodeData
(
request
*
fetchRequest
)
error
{
// Sanity check the protocol version
if
p
.
version
<
63
{
panic
(
fmt
.
Sprintf
(
"node data fetch [eth/63+] requested on eth/%d"
,
p
.
version
))
}
// Short circuit if the peer is already fetching
if
!
atomic
.
CompareAndSwapInt32
(
&
p
.
stateIdle
,
0
,
1
)
{
return
errAlreadyFetching
...
...
@@ -196,35 +212,35 @@ func (p *peer) FetchNodeData(request *fetchRequest) error {
// SetBlocksIdle sets the peer to idle, allowing it to execute new retrieval requests.
// Its block retrieval allowance will also be updated either up- or downwards,
// depending on whether the previous fetch completed in time
or not
.
// depending on whether the previous fetch completed in time.
func
(
p
*
peer
)
SetBlocksIdle
()
{
p
.
setIdle
(
p
.
blockStarted
,
blockSoftTTL
,
blockHardTTL
,
MaxBlockFetch
,
&
p
.
blockCapacity
,
&
p
.
blockIdle
)
}
// SetBodiesIdle sets the peer to idle, allowing it to execute new retrieval requests.
// Its block body retrieval allowance will also be updated either up- or downwards,
// depending on whether the previous fetch completed in time
or not
.
// depending on whether the previous fetch completed in time.
func
(
p
*
peer
)
SetBodiesIdle
()
{
p
.
setIdle
(
p
.
blockStarted
,
bodySoftTTL
,
bodyHardTTL
,
MaxB
lock
Fetch
,
&
p
.
blockCapacity
,
&
p
.
blockIdle
)
p
.
setIdle
(
p
.
blockStarted
,
bodySoftTTL
,
bodyHardTTL
,
MaxB
ody
Fetch
,
&
p
.
blockCapacity
,
&
p
.
blockIdle
)
}
// SetReceiptsIdle sets the peer to idle, allowing it to execute new retrieval requests.
// Its receipt retrieval allowance will also be updated either up- or downwards,
// depending on whether the previous fetch completed in time
or not
.
// depending on whether the previous fetch completed in time.
func
(
p
*
peer
)
SetReceiptsIdle
()
{
p
.
setIdle
(
p
.
receiptStarted
,
receiptSoftTTL
,
receiptHardTTL
,
MaxReceiptFetch
,
&
p
.
receiptCapacity
,
&
p
.
receiptIdle
)
}
// SetNodeDataIdle sets the peer to idle, allowing it to execute new retrieval
// requests. Its node data retrieval allowance will also be updated either up- or
// downwards, depending on whether the previous fetch completed in time
or not
.
// downwards, depending on whether the previous fetch completed in time.
func
(
p
*
peer
)
SetNodeDataIdle
()
{
p
.
setIdle
(
p
.
stateStarted
,
stateSoftTTL
,
stateSoftTTL
,
MaxStateFetch
,
&
p
.
stateCapacity
,
&
p
.
stateIdle
)
}
// setIdle sets the peer to idle, allowing it to execute new retrieval requests.
// Its data retrieval allowance will also be updated either up- or downwards,
// depending on whether the previous fetch completed in time
or not
.
// depending on whether the previous fetch completed in time.
func
(
p
*
peer
)
setIdle
(
started
time
.
Time
,
softTTL
,
hardTTL
time
.
Duration
,
maxFetch
int
,
capacity
,
idle
*
int32
)
{
// Update the peer's download allowance based on previous performance
scale
:=
2.0
...
...
eth/downloader/queue.go
浏览文件 @
5b0ee8ec
...
...
@@ -56,9 +56,8 @@ type fetchRequest struct {
Time
time
.
Time
// Time when the request was made
}
// fetchResult is the assembly collecting partial results from potentially more
// than one fetcher routines, until all outstanding retrievals complete and the
// result as a whole can be processed.
// fetchResult is a struct collecting partial results from data fetchers until
// all outstanding pieces complete and the result as a whole can be processed.
type
fetchResult
struct
{
Pending
int
// Number of data fetches still pending
...
...
@@ -89,7 +88,7 @@ type queue struct {
receiptPendPool
map
[
string
]
*
fetchRequest
// [eth/63] Currently pending receipt retrieval operations
receiptDonePool
map
[
common
.
Hash
]
struct
{}
// [eth/63] Set of the completed receipt fetches
stateTaskIndex
int
// [eth/63] Counter indexing the added hashes to ensure prioriti
z
ed retrieval order
stateTaskIndex
int
// [eth/63] Counter indexing the added hashes to ensure prioriti
s
ed retrieval order
stateTaskPool
map
[
common
.
Hash
]
int
// [eth/63] Pending node data retrieval tasks, mapping to their priority
stateTaskQueue
*
prque
.
Prque
// [eth/63] Priority queue of the hashes to fetch the node data for
statePendPool
map
[
string
]
*
fetchRequest
// [eth/63] Currently pending node data retrieval operations
...
...
@@ -97,10 +96,10 @@ type queue struct {
stateDatabase
ethdb
.
Database
// [eth/63] Trie database to populate during state reassembly
stateScheduler
*
state
.
StateSync
// [eth/63] State trie synchronisation scheduler and integrator
stateProcessors
int32
// [eth/63] Number of currently running state processors
stateSchedLock
sync
.
RWMutex
// [eth/63] Lock seriali
z
ing access to the state scheduler
stateSchedLock
sync
.
RWMutex
// [eth/63] Lock seriali
s
ing access to the state scheduler
resultCache
[]
*
fetchResult
// Downloaded but not yet delivered fetch results
resultOffset
uint64
// Offset of the first cached fetch result in the block
-
chain
resultOffset
uint64
// Offset of the first cached fetch result in the block
chain
lock
sync
.
RWMutex
}
...
...
@@ -131,6 +130,9 @@ func (q *queue) Reset() {
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
q
.
stateSchedLock
.
Lock
()
defer
q
.
stateSchedLock
.
Unlock
()
q
.
mode
=
FullSync
q
.
fastSyncPivot
=
0
...
...
@@ -233,9 +235,17 @@ func (q *queue) Idle() bool {
return
(
queued
+
pending
+
cached
)
==
0
}
// ThrottleBlocks checks if the download should be throttled (active block (body)
// FastSyncPivot retrieves the currently used fast sync pivot point.
func
(
q
*
queue
)
FastSyncPivot
()
uint64
{
q
.
lock
.
RLock
()
defer
q
.
lock
.
RUnlock
()
return
q
.
fastSyncPivot
}
// ShouldThrottleBlocks checks if the download should be throttled (active block (body)
// fetches exceed block cache).
func
(
q
*
queue
)
ThrottleBlocks
()
bool
{
func
(
q
*
queue
)
Should
ThrottleBlocks
()
bool
{
q
.
lock
.
RLock
()
defer
q
.
lock
.
RUnlock
()
...
...
@@ -248,9 +258,9 @@ func (q *queue) ThrottleBlocks() bool {
return
pending
>=
len
(
q
.
resultCache
)
-
len
(
q
.
blockDonePool
)
}
// ThrottleReceipts checks if the download should be throttled (active receipt
//
Should
ThrottleReceipts checks if the download should be throttled (active receipt
// fetches exceed block cache).
func
(
q
*
queue
)
ThrottleReceipts
()
bool
{
func
(
q
*
queue
)
Should
ThrottleReceipts
()
bool
{
q
.
lock
.
RLock
()
defer
q
.
lock
.
RUnlock
()
...
...
@@ -269,7 +279,7 @@ func (q *queue) Schedule61(hashes []common.Hash, fifo bool) []common.Hash {
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
// Insert all the hashes prioriti
z
ed in the arrival order
// Insert all the hashes prioriti
s
ed in the arrival order
inserts
:=
make
([]
common
.
Hash
,
0
,
len
(
hashes
))
for
_
,
hash
:=
range
hashes
{
// Skip anything we already have
...
...
@@ -297,10 +307,10 @@ func (q *queue) Schedule(headers []*types.Header, from uint64) []*types.Header {
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
// Insert all the headers prioriti
z
ed by the contained block number
// Insert all the headers prioriti
s
ed by the contained block number
inserts
:=
make
([]
*
types
.
Header
,
0
,
len
(
headers
))
for
_
,
header
:=
range
headers
{
// Make sure chain order is honored and preserved throughout
// Make sure chain order is hono
u
red and preserved throughout
hash
:=
header
.
Hash
()
if
header
.
Number
==
nil
||
header
.
Number
.
Uint64
()
!=
from
{
glog
.
V
(
logger
.
Warn
)
.
Infof
(
"Header #%v [%x] broke chain ordering, expected %d"
,
header
.
Number
,
hash
[
:
4
],
from
)
...
...
@@ -347,19 +357,29 @@ func (q *queue) GetHeadResult() *fetchResult {
q
.
lock
.
RLock
()
defer
q
.
lock
.
RUnlock
()
// If there are no results pending, return nil
if
len
(
q
.
resultCache
)
==
0
||
q
.
resultCache
[
0
]
==
nil
{
return
nil
}
// If the next result is still incomplete, return nil
if
q
.
resultCache
[
0
]
.
Pending
>
0
{
return
nil
}
// If the next result is the fast sync pivot...
if
q
.
mode
==
FastSync
&&
q
.
resultCache
[
0
]
.
Header
.
Number
.
Uint64
()
==
q
.
fastSyncPivot
{
// If the pivot state trie is still being pulled, return nil
if
len
(
q
.
stateTaskPool
)
>
0
{
return
nil
}
if
q
.
PendingNodeData
()
>
0
{
return
nil
}
// If the state is done, but not enough post-pivot headers were verified, stall...
for
i
:=
0
;
i
<
fsHeaderForceVerify
;
i
++
{
if
i
+
1
>=
len
(
q
.
resultCache
)
||
q
.
resultCache
[
i
+
1
]
==
nil
{
return
nil
}
}
}
return
q
.
resultCache
[
0
]
}
...
...
@@ -372,7 +392,7 @@ func (q *queue) TakeResults() []*fetchResult {
// Accumulate all available results
results
:=
[]
*
fetchResult
{}
for
_
,
result
:=
range
q
.
resultCache
{
for
i
,
result
:=
range
q
.
resultCache
{
// Stop if no more results are ready
if
result
==
nil
||
result
.
Pending
>
0
{
break
...
...
@@ -385,6 +405,16 @@ func (q *queue) TakeResults() []*fetchResult {
if
q
.
PendingNodeData
()
>
0
{
break
}
// Even is state fetch is done, ensure post-pivot headers passed verifications
safe
:=
true
for
j
:=
0
;
j
<
fsHeaderForceVerify
;
j
++
{
if
i
+
j
+
1
>=
len
(
q
.
resultCache
)
||
q
.
resultCache
[
i
+
j
+
1
]
==
nil
{
safe
=
false
}
}
if
!
safe
{
break
}
}
// If we've just inserted the fast sync pivot, stop as the following batch needs different insertion
if
q
.
mode
==
FastSync
&&
result
.
Header
.
Number
.
Uint64
()
==
q
.
fastSyncPivot
+
1
&&
len
(
results
)
>
0
{
...
...
@@ -411,6 +441,9 @@ func (q *queue) TakeResults() []*fetchResult {
// ReserveBlocks reserves a set of block hashes for the given peer, skipping any
// previously failed download.
func
(
q
*
queue
)
ReserveBlocks
(
p
*
peer
,
count
int
)
*
fetchRequest
{
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
return
q
.
reserveHashes
(
p
,
count
,
q
.
hashQueue
,
nil
,
q
.
blockPendPool
,
len
(
q
.
resultCache
)
-
len
(
q
.
blockDonePool
))
}
...
...
@@ -430,17 +463,21 @@ func (q *queue) ReserveNodeData(p *peer, count int) *fetchRequest {
}
}
}
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
return
q
.
reserveHashes
(
p
,
count
,
q
.
stateTaskQueue
,
generator
,
q
.
statePendPool
,
count
)
}
// reserveHashes reserves a set of hashes for the given peer, skipping previously
// failed ones.
//
// Note, this method expects the queue lock to be already held for writing. The
// reason the lock is not obtained in here is because the parameters already need
// to access the queue, so they already need a lock anyway.
func
(
q
*
queue
)
reserveHashes
(
p
*
peer
,
count
int
,
taskQueue
*
prque
.
Prque
,
taskGen
func
(
int
),
pendPool
map
[
string
]
*
fetchRequest
,
maxPending
int
)
*
fetchRequest
{
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
// Short circuit if the peer's already downloading something (sanity check not
// to corrupt state)
// Short circuit if the peer's already downloading something (sanity check to
// not corrupt state)
if
_
,
ok
:=
pendPool
[
p
.
id
];
ok
{
return
nil
}
...
...
@@ -492,30 +529,37 @@ func (q *queue) reserveHashes(p *peer, count int, taskQueue *prque.Prque, taskGe
// previously failed downloads. Beside the next batch of needed fetches, it also
// returns a flag whether empty blocks were queued requiring processing.
func
(
q
*
queue
)
ReserveBodies
(
p
*
peer
,
count
int
)
(
*
fetchRequest
,
bool
,
error
)
{
n
oop
:=
func
(
header
*
types
.
Header
)
bool
{
isN
oop
:=
func
(
header
*
types
.
Header
)
bool
{
return
header
.
TxHash
==
types
.
EmptyRootHash
&&
header
.
UncleHash
==
types
.
EmptyUncleHash
}
return
q
.
reserveHeaders
(
p
,
count
,
q
.
blockTaskPool
,
q
.
blockTaskQueue
,
q
.
blockPendPool
,
q
.
blockDonePool
,
noop
)
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
return
q
.
reserveHeaders
(
p
,
count
,
q
.
blockTaskPool
,
q
.
blockTaskQueue
,
q
.
blockPendPool
,
q
.
blockDonePool
,
isNoop
)
}
// ReserveReceipts reserves a set of receipt fetches for the given peer, skipping
// any previously failed downloads. Beside the next batch of needed fetches, it
// also returns a flag whether empty receipts were queued requiring importing.
func
(
q
*
queue
)
ReserveReceipts
(
p
*
peer
,
count
int
)
(
*
fetchRequest
,
bool
,
error
)
{
n
oop
:=
func
(
header
*
types
.
Header
)
bool
{
isN
oop
:=
func
(
header
*
types
.
Header
)
bool
{
return
header
.
ReceiptHash
==
types
.
EmptyRootHash
}
return
q
.
reserveHeaders
(
p
,
count
,
q
.
receiptTaskPool
,
q
.
receiptTaskQueue
,
q
.
receiptPendPool
,
q
.
receiptDonePool
,
noop
)
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
return
q
.
reserveHeaders
(
p
,
count
,
q
.
receiptTaskPool
,
q
.
receiptTaskQueue
,
q
.
receiptPendPool
,
q
.
receiptDonePool
,
isNoop
)
}
// reserveHeaders reserves a set of data download operations for a given peer,
// skipping any previously failed ones. This method is a generic version used
// by the individual special reservation functions.
//
// Note, this method expects the queue lock to be already held for writing. The
// reason the lock is not obtained in here is because the parameters already need
// to access the queue, so they already need a lock anyway.
func
(
q
*
queue
)
reserveHeaders
(
p
*
peer
,
count
int
,
taskPool
map
[
common
.
Hash
]
*
types
.
Header
,
taskQueue
*
prque
.
Prque
,
pendPool
map
[
string
]
*
fetchRequest
,
donePool
map
[
common
.
Hash
]
struct
{},
noop
func
(
*
types
.
Header
)
bool
)
(
*
fetchRequest
,
bool
,
error
)
{
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
pendPool
map
[
string
]
*
fetchRequest
,
donePool
map
[
common
.
Hash
]
struct
{},
isNoop
func
(
*
types
.
Header
)
bool
)
(
*
fetchRequest
,
bool
,
error
)
{
// Short circuit if the pool has been depleted, or if the peer's already
// downloading something (sanity check not to corrupt state)
if
taskQueue
.
Empty
()
{
...
...
@@ -537,7 +581,7 @@ func (q *queue) reserveHeaders(p *peer, count int, taskPool map[common.Hash]*typ
for
proc
:=
0
;
proc
<
space
&&
len
(
send
)
<
count
&&
!
taskQueue
.
Empty
();
proc
++
{
header
:=
taskQueue
.
PopItem
()
.
(
*
types
.
Header
)
// If we're the first to request this task, initiali
z
e the result container
// If we're the first to request this task, initiali
s
e the result container
index
:=
int
(
header
.
Number
.
Int64
()
-
int64
(
q
.
resultOffset
))
if
index
>=
len
(
q
.
resultCache
)
||
index
<
0
{
return
nil
,
false
,
errInvalidChain
...
...
@@ -553,7 +597,7 @@ func (q *queue) reserveHeaders(p *peer, count int, taskPool map[common.Hash]*typ
}
}
// If this fetch task is a noop, skip this fetch operation
if
n
oop
(
header
)
{
if
isN
oop
(
header
)
{
donePool
[
header
.
Hash
()]
=
struct
{}{}
delete
(
taskPool
,
header
.
Hash
())
...
...
@@ -562,7 +606,7 @@ func (q *queue) reserveHeaders(p *peer, count int, taskPool map[common.Hash]*typ
progress
=
true
continue
}
// Otherwise
if not a known unknown block
, add to the retrieve list
// Otherwise
unless the peer is known not to have the data
, add to the retrieve list
if
p
.
ignored
.
Has
(
header
.
Hash
())
{
skip
=
append
(
skip
,
header
)
}
else
{
...
...
@@ -655,35 +699,48 @@ func (q *queue) Revoke(peerId string) {
}
// ExpireBlocks checks for in flight requests that exceeded a timeout allowance,
// canceling them and returning the responsible peers for penali
z
ation.
// canceling them and returning the responsible peers for penali
s
ation.
func
(
q
*
queue
)
ExpireBlocks
(
timeout
time
.
Duration
)
[]
string
{
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
return
q
.
expire
(
timeout
,
q
.
blockPendPool
,
q
.
hashQueue
,
blockTimeoutMeter
)
}
// ExpireBodies checks for in flight block body requests that exceeded a timeout
// allowance, canceling them and returning the responsible peers for penali
z
ation.
// allowance, canceling them and returning the responsible peers for penali
s
ation.
func
(
q
*
queue
)
ExpireBodies
(
timeout
time
.
Duration
)
[]
string
{
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
return
q
.
expire
(
timeout
,
q
.
blockPendPool
,
q
.
blockTaskQueue
,
bodyTimeoutMeter
)
}
// ExpireReceipts checks for in flight receipt requests that exceeded a timeout
// allowance, canceling them and returning the responsible peers for penali
z
ation.
// allowance, canceling them and returning the responsible peers for penali
s
ation.
func
(
q
*
queue
)
ExpireReceipts
(
timeout
time
.
Duration
)
[]
string
{
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
return
q
.
expire
(
timeout
,
q
.
receiptPendPool
,
q
.
receiptTaskQueue
,
receiptTimeoutMeter
)
}
// ExpireNodeData checks for in flight node data requests that exceeded a timeout
// allowance, canceling them and returning the responsible peers for penali
z
ation.
// allowance, canceling them and returning the responsible peers for penali
s
ation.
func
(
q
*
queue
)
ExpireNodeData
(
timeout
time
.
Duration
)
[]
string
{
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
return
q
.
expire
(
timeout
,
q
.
statePendPool
,
q
.
stateTaskQueue
,
stateTimeoutMeter
)
}
// expire is the generic check that move expired tasks from a pending pool back
// into a task pool, returning all entities caught with expired tasks.
//
// Note, this method expects the queue lock to be already held for writing. The
// reason the lock is not obtained in here is because the parameters already need
// to access the queue, so they already need a lock anyway.
func
(
q
*
queue
)
expire
(
timeout
time
.
Duration
,
pendPool
map
[
string
]
*
fetchRequest
,
taskQueue
*
prque
.
Prque
,
timeoutMeter
metrics
.
Meter
)
[]
string
{
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
// Iterate over the expired requests and return each to the queue
peers
:=
[]
string
{}
for
id
,
request
:=
range
pendPool
{
...
...
@@ -764,7 +821,7 @@ func (q *queue) DeliverBlocks(id string, blocks []*types.Block) error {
case
len
(
errs
)
==
1
&&
(
errs
[
0
]
==
errInvalidChain
||
errs
[
0
]
==
errInvalidBlock
)
:
return
errs
[
0
]
case
len
(
errs
)
==
len
(
request
.
Header
s
)
:
case
len
(
errs
)
==
len
(
block
s
)
:
return
errStaleDelivery
default
:
...
...
@@ -774,6 +831,9 @@ func (q *queue) DeliverBlocks(id string, blocks []*types.Block) error {
// DeliverBodies injects a block body retrieval response into the results queue.
func
(
q
*
queue
)
DeliverBodies
(
id
string
,
txLists
[][]
*
types
.
Transaction
,
uncleLists
[][]
*
types
.
Header
)
error
{
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
reconstruct
:=
func
(
header
*
types
.
Header
,
index
int
,
result
*
fetchResult
)
error
{
if
types
.
DeriveSha
(
types
.
Transactions
(
txLists
[
index
]))
!=
header
.
TxHash
||
types
.
CalcUncleHash
(
uncleLists
[
index
])
!=
header
.
UncleHash
{
return
errInvalidBody
...
...
@@ -787,6 +847,9 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, uncleLi
// DeliverReceipts injects a receipt retrieval response into the results queue.
func
(
q
*
queue
)
DeliverReceipts
(
id
string
,
receiptList
[][]
*
types
.
Receipt
)
error
{
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
reconstruct
:=
func
(
header
*
types
.
Header
,
index
int
,
result
*
fetchResult
)
error
{
if
types
.
DeriveSha
(
types
.
Receipts
(
receiptList
[
index
]))
!=
header
.
ReceiptHash
{
return
errInvalidReceipt
...
...
@@ -798,11 +861,12 @@ func (q *queue) DeliverReceipts(id string, receiptList [][]*types.Receipt) error
}
// deliver injects a data retrieval response into the results queue.
//
// Note, this method expects the queue lock to be already held for writing. The
// reason the lock is not obtained in here is because the parameters already need
// to access the queue, so they already need a lock anyway.
func
(
q
*
queue
)
deliver
(
id
string
,
taskPool
map
[
common
.
Hash
]
*
types
.
Header
,
taskQueue
*
prque
.
Prque
,
pendPool
map
[
string
]
*
fetchRequest
,
donePool
map
[
common
.
Hash
]
struct
{},
reqTimer
metrics
.
Timer
,
results
int
,
reconstruct
func
(
header
*
types
.
Header
,
index
int
,
result
*
fetchResult
)
error
)
error
{
q
.
lock
.
Lock
()
defer
q
.
lock
.
Unlock
()
// Short circuit if the data was never requested
request
:=
pendPool
[
id
]
if
request
==
nil
{
...
...
@@ -818,7 +882,10 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, taskQ
}
}
// Assemble each of the results with their headers and retrieved data parts
errs
:=
make
([]
error
,
0
)
var
(
failure
error
useful
bool
)
for
i
,
header
:=
range
request
.
Headers
{
// Short circuit assembly if no more fetch results are found
if
i
>=
results
{
...
...
@@ -827,15 +894,16 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, taskQ
// Reconstruct the next result if contents match up
index
:=
int
(
header
.
Number
.
Int64
()
-
int64
(
q
.
resultOffset
))
if
index
>=
len
(
q
.
resultCache
)
||
index
<
0
||
q
.
resultCache
[
index
]
==
nil
{
errs
=
[]
error
{
errInvalidChain
}
failure
=
errInvalidChain
break
}
if
err
:=
reconstruct
(
header
,
i
,
q
.
resultCache
[
index
]);
err
!=
nil
{
errs
=
[]
error
{
err
}
failure
=
err
break
}
donePool
[
header
.
Hash
()]
=
struct
{}{}
q
.
resultCache
[
index
]
.
Pending
--
useful
=
true
// Clean up a successful fetch
request
.
Headers
[
i
]
=
nil
...
...
@@ -847,19 +915,16 @@ func (q *queue) deliver(id string, taskPool map[common.Hash]*types.Header, taskQ
taskQueue
.
Push
(
header
,
-
float32
(
header
.
Number
.
Uint64
()))
}
}
// If none of the
blocks were
good, it's a stale delivery
// If none of the
data was
good, it's a stale delivery
switch
{
case
len
(
errs
)
==
0
:
return
nil
case
len
(
errs
)
==
1
&&
(
errs
[
0
]
==
errInvalidChain
||
errs
[
0
]
==
errInvalidBody
||
errs
[
0
]
==
errInvalidReceipt
)
:
return
errs
[
0
]
case
failure
==
nil
||
failure
==
errInvalidChain
:
return
failure
case
len
(
errs
)
==
len
(
request
.
Headers
)
:
return
errStaleDelivery
case
useful
:
return
fmt
.
Errorf
(
"partial failure: %v"
,
failure
)
default
:
return
fmt
.
Errorf
(
"multiple failures: %v"
,
errs
)
return
errStaleDelivery
}
}
...
...
@@ -876,7 +941,7 @@ func (q *queue) DeliverNodeData(id string, data [][]byte, callback func(error, i
stateReqTimer
.
UpdateSince
(
request
.
Time
)
delete
(
q
.
statePendPool
,
id
)
// If no data was retrieved, mark the
m
as unavailable for the origin peer
// If no data was retrieved, mark the
ir hashes
as unavailable for the origin peer
if
len
(
data
)
==
0
{
for
hash
,
_
:=
range
request
.
Hashes
{
request
.
Peer
.
ignored
.
Add
(
hash
)
...
...
@@ -955,9 +1020,6 @@ func (q *queue) Prepare(offset uint64, mode SyncMode, pivot uint64) {
if
q
.
resultOffset
<
offset
{
q
.
resultOffset
=
offset
}
q
.
fastSyncPivot
=
0
if
mode
==
FastSync
{
q
.
fastSyncPivot
=
pivot
}
q
.
fastSyncPivot
=
pivot
q
.
mode
=
mode
}
eth/fetcher/fetcher.go
浏览文件 @
5b0ee8ec
...
...
@@ -142,9 +142,11 @@ type Fetcher struct {
dropPeer
peerDropFn
// Drops a peer for misbehaving
// Testing hooks
fetchingHook
func
([]
common
.
Hash
)
// Method to call upon starting a block (eth/61) or header (eth/62) fetch
completingHook
func
([]
common
.
Hash
)
// Method to call upon starting a block body fetch (eth/62)
importedHook
func
(
*
types
.
Block
)
// Method to call upon successful block import (both eth/61 and eth/62)
announceChangeHook
func
(
common
.
Hash
,
bool
)
// Method to call upon adding or deleting a hash from the announce list
queueChangeHook
func
(
common
.
Hash
,
bool
)
// Method to call upon adding or deleting a block from the import queue
fetchingHook
func
([]
common
.
Hash
)
// Method to call upon starting a block (eth/61) or header (eth/62) fetch
completingHook
func
([]
common
.
Hash
)
// Method to call upon starting a block body fetch (eth/62)
importedHook
func
(
*
types
.
Block
)
// Method to call upon successful block import (both eth/61 and eth/62)
}
// New creates a block fetcher to retrieve blocks based on hash announcements.
...
...
@@ -324,11 +326,16 @@ func (f *Fetcher) loop() {
height
:=
f
.
chainHeight
()
for
!
f
.
queue
.
Empty
()
{
op
:=
f
.
queue
.
PopItem
()
.
(
*
inject
)
if
f
.
queueChangeHook
!=
nil
{
f
.
queueChangeHook
(
op
.
block
.
Hash
(),
false
)
}
// If too high up the chain or phase, continue later
number
:=
op
.
block
.
NumberU64
()
if
number
>
height
+
1
{
f
.
queue
.
Push
(
op
,
-
float32
(
op
.
block
.
NumberU64
()))
if
f
.
queueChangeHook
!=
nil
{
f
.
queueChangeHook
(
op
.
block
.
Hash
(),
true
)
}
break
}
// Otherwise if fresh and still unknown, try and import
...
...
@@ -372,6 +379,9 @@ func (f *Fetcher) loop() {
}
f
.
announces
[
notification
.
origin
]
=
count
f
.
announced
[
notification
.
hash
]
=
append
(
f
.
announced
[
notification
.
hash
],
notification
)
if
f
.
announceChangeHook
!=
nil
&&
len
(
f
.
announced
[
notification
.
hash
])
==
1
{
f
.
announceChangeHook
(
notification
.
hash
,
true
)
}
if
len
(
f
.
announced
)
==
1
{
f
.
rescheduleFetch
(
fetchTimer
)
}
...
...
@@ -714,7 +724,9 @@ func (f *Fetcher) enqueue(peer string, block *types.Block) {
f
.
queues
[
peer
]
=
count
f
.
queued
[
hash
]
=
op
f
.
queue
.
Push
(
op
,
-
float32
(
block
.
NumberU64
()))
if
f
.
queueChangeHook
!=
nil
{
f
.
queueChangeHook
(
op
.
block
.
Hash
(),
true
)
}
if
glog
.
V
(
logger
.
Debug
)
{
glog
.
Infof
(
"Peer %s: queued block #%d [%x…], total %v"
,
peer
,
block
.
NumberU64
(),
hash
.
Bytes
()[
:
4
],
f
.
queue
.
Size
())
}
...
...
@@ -781,7 +793,9 @@ func (f *Fetcher) forgetHash(hash common.Hash) {
}
}
delete
(
f
.
announced
,
hash
)
if
f
.
announceChangeHook
!=
nil
{
f
.
announceChangeHook
(
hash
,
false
)
}
// Remove any pending fetches and decrement the DOS counters
if
announce
:=
f
.
fetching
[
hash
];
announce
!=
nil
{
f
.
announces
[
announce
.
origin
]
--
...
...
eth/fetcher/fetcher_test.go
浏览文件 @
5b0ee8ec
...
...
@@ -145,6 +145,9 @@ func (f *fetcherTester) insertChain(blocks types.Blocks) (int, error) {
// dropPeer is an emulator for the peer removal, simply accumulating the various
// peers dropped by the fetcher.
func
(
f
*
fetcherTester
)
dropPeer
(
peer
string
)
{
f
.
lock
.
Lock
()
defer
f
.
lock
.
Unlock
()
f
.
drops
[
peer
]
=
true
}
...
...
@@ -608,8 +611,11 @@ func TestDistantPropagationDiscarding(t *testing.T) {
// Create a tester and simulate a head block being the middle of the above chain
tester
:=
newTester
()
tester
.
lock
.
Lock
()
tester
.
hashes
=
[]
common
.
Hash
{
head
}
tester
.
blocks
=
map
[
common
.
Hash
]
*
types
.
Block
{
head
:
blocks
[
head
]}
tester
.
lock
.
Unlock
()
// Ensure that a block with a lower number than the threshold is discarded
tester
.
fetcher
.
Enqueue
(
"lower"
,
blocks
[
hashes
[
low
]])
...
...
@@ -641,8 +647,11 @@ func testDistantAnnouncementDiscarding(t *testing.T, protocol int) {
// Create a tester and simulate a head block being the middle of the above chain
tester
:=
newTester
()
tester
.
lock
.
Lock
()
tester
.
hashes
=
[]
common
.
Hash
{
head
}
tester
.
blocks
=
map
[
common
.
Hash
]
*
types
.
Block
{
head
:
blocks
[
head
]}
tester
.
lock
.
Unlock
()
headerFetcher
:=
tester
.
makeHeaderFetcher
(
blocks
,
-
gatherSlack
)
bodyFetcher
:=
tester
.
makeBodyFetcher
(
blocks
,
0
)
...
...
@@ -687,14 +696,22 @@ func testInvalidNumberAnnouncement(t *testing.T, protocol int) {
tester
.
fetcher
.
Notify
(
"bad"
,
hashes
[
0
],
2
,
time
.
Now
()
.
Add
(
-
arriveTimeout
),
nil
,
headerFetcher
,
bodyFetcher
)
verifyImportEvent
(
t
,
imported
,
false
)
if
!
tester
.
drops
[
"bad"
]
{
tester
.
lock
.
RLock
()
dropped
:=
tester
.
drops
[
"bad"
]
tester
.
lock
.
RUnlock
()
if
!
dropped
{
t
.
Fatalf
(
"peer with invalid numbered announcement not dropped"
)
}
// Make sure a good announcement passes without a drop
tester
.
fetcher
.
Notify
(
"good"
,
hashes
[
0
],
1
,
time
.
Now
()
.
Add
(
-
arriveTimeout
),
nil
,
headerFetcher
,
bodyFetcher
)
verifyImportEvent
(
t
,
imported
,
true
)
if
tester
.
drops
[
"good"
]
{
tester
.
lock
.
RLock
()
dropped
=
tester
.
drops
[
"good"
]
tester
.
lock
.
RUnlock
()
if
dropped
{
t
.
Fatalf
(
"peer with valid numbered announcement dropped"
)
}
verifyImportDone
(
t
,
imported
)
...
...
@@ -752,9 +769,15 @@ func testHashMemoryExhaustionAttack(t *testing.T, protocol int) {
// Create a tester with instrumented import hooks
tester
:=
newTester
()
imported
:=
make
(
chan
*
types
.
Block
)
imported
,
announces
:=
make
(
chan
*
types
.
Block
),
int32
(
0
)
tester
.
fetcher
.
importedHook
=
func
(
block
*
types
.
Block
)
{
imported
<-
block
}
tester
.
fetcher
.
announceChangeHook
=
func
(
hash
common
.
Hash
,
added
bool
)
{
if
added
{
atomic
.
AddInt32
(
&
announces
,
1
)
}
else
{
atomic
.
AddInt32
(
&
announces
,
-
1
)
}
}
// Create a valid chain and an infinite junk chain
targetBlocks
:=
hashLimit
+
2
*
maxQueueDist
hashes
,
blocks
:=
makeChain
(
targetBlocks
,
0
,
genesis
)
...
...
@@ -782,8 +805,8 @@ func testHashMemoryExhaustionAttack(t *testing.T, protocol int) {
tester
.
fetcher
.
Notify
(
"attacker"
,
attack
[
i
],
1
/* don't distance drop */
,
time
.
Now
(),
nil
,
attackerHeaderFetcher
,
attackerBodyFetcher
)
}
}
if
len
(
tester
.
fetcher
.
announced
)
!=
hashLimit
+
maxQueueDist
{
t
.
Fatalf
(
"queued announce count mismatch: have %d, want %d"
,
len
(
tester
.
fetcher
.
announced
)
,
hashLimit
+
maxQueueDist
)
if
count
:=
atomic
.
LoadInt32
(
&
announces
);
count
!=
hashLimit
+
maxQueueDist
{
t
.
Fatalf
(
"queued announce count mismatch: have %d, want %d"
,
count
,
hashLimit
+
maxQueueDist
)
}
// Wait for fetches to complete
verifyImportCount
(
t
,
imported
,
maxQueueDist
)
...
...
@@ -807,9 +830,15 @@ func TestBlockMemoryExhaustionAttack(t *testing.T) {
// Create a tester with instrumented import hooks
tester
:=
newTester
()
imported
:=
make
(
chan
*
types
.
Block
)
imported
,
enqueued
:=
make
(
chan
*
types
.
Block
),
int32
(
0
)
tester
.
fetcher
.
importedHook
=
func
(
block
*
types
.
Block
)
{
imported
<-
block
}
tester
.
fetcher
.
queueChangeHook
=
func
(
hash
common
.
Hash
,
added
bool
)
{
if
added
{
atomic
.
AddInt32
(
&
enqueued
,
1
)
}
else
{
atomic
.
AddInt32
(
&
enqueued
,
-
1
)
}
}
// Create a valid chain and a batch of dangling (but in range) blocks
targetBlocks
:=
hashLimit
+
2
*
maxQueueDist
hashes
,
blocks
:=
makeChain
(
targetBlocks
,
0
,
genesis
)
...
...
@@ -825,7 +854,7 @@ func TestBlockMemoryExhaustionAttack(t *testing.T) {
tester
.
fetcher
.
Enqueue
(
"attacker"
,
block
)
}
time
.
Sleep
(
200
*
time
.
Millisecond
)
if
queued
:=
tester
.
fetcher
.
queue
.
Size
(
);
queued
!=
blockLimit
{
if
queued
:=
atomic
.
LoadInt32
(
&
enqueued
);
queued
!=
blockLimit
{
t
.
Fatalf
(
"queued block count mismatch: have %d, want %d"
,
queued
,
blockLimit
)
}
// Queue up a batch of valid blocks, and check that a new peer is allowed to do so
...
...
@@ -833,7 +862,7 @@ func TestBlockMemoryExhaustionAttack(t *testing.T) {
tester
.
fetcher
.
Enqueue
(
"valid"
,
blocks
[
hashes
[
len
(
hashes
)
-
3
-
i
]])
}
time
.
Sleep
(
100
*
time
.
Millisecond
)
if
queued
:=
tester
.
fetcher
.
queue
.
Size
(
);
queued
!=
blockLimit
+
maxQueueDist
-
1
{
if
queued
:=
atomic
.
LoadInt32
(
&
enqueued
);
queued
!=
blockLimit
+
maxQueueDist
-
1
{
t
.
Fatalf
(
"queued block count mismatch: have %d, want %d"
,
queued
,
blockLimit
+
maxQueueDist
-
1
)
}
// Insert the missing piece (and sanity check the import)
...
...
eth/filters/filter_test.go
浏览文件 @
5b0ee8ec
...
...
@@ -16,9 +16,9 @@ import (
func
makeReceipt
(
addr
common
.
Address
)
*
types
.
Receipt
{
receipt
:=
types
.
NewReceipt
(
nil
,
new
(
big
.
Int
))
receipt
.
SetLogs
(
vm
.
Logs
{
receipt
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
addr
},
}
)
}
receipt
.
Bloom
=
types
.
CreateBloom
(
types
.
Receipts
{
receipt
})
return
receipt
}
...
...
@@ -41,7 +41,7 @@ func BenchmarkMipmaps(b *testing.B) {
defer
db
.
Close
()
genesis
:=
core
.
WriteGenesisBlockForTesting
(
db
,
core
.
GenesisAccount
{
addr1
,
big
.
NewInt
(
1000000
)})
chain
:=
core
.
GenerateChain
(
genesis
,
db
,
100010
,
func
(
i
int
,
gen
*
core
.
BlockGen
)
{
chain
,
receipts
:=
core
.
GenerateChain
(
genesis
,
db
,
100010
,
func
(
i
int
,
gen
*
core
.
BlockGen
)
{
var
receipts
types
.
Receipts
switch
i
{
case
2403
:
...
...
@@ -70,7 +70,7 @@ func BenchmarkMipmaps(b *testing.B) {
}
core
.
WriteMipmapBloom
(
db
,
uint64
(
i
+
1
),
receipts
)
})
for
_
,
block
:=
range
chain
{
for
i
,
block
:=
range
chain
{
core
.
WriteBlock
(
db
,
block
)
if
err
:=
core
.
WriteCanonicalHash
(
db
,
block
.
Hash
(),
block
.
NumberU64
());
err
!=
nil
{
b
.
Fatalf
(
"failed to insert block number: %v"
,
err
)
...
...
@@ -78,11 +78,10 @@ func BenchmarkMipmaps(b *testing.B) {
if
err
:=
core
.
WriteHeadBlockHash
(
db
,
block
.
Hash
());
err
!=
nil
{
b
.
Fatalf
(
"failed to insert block number: %v"
,
err
)
}
if
err
:=
core
.
PutBlockReceipts
(
db
,
block
,
block
.
Receipts
()
);
err
!=
nil
{
if
err
:=
core
.
PutBlockReceipts
(
db
,
block
.
Hash
(),
receipts
[
i
]
);
err
!=
nil
{
b
.
Fatal
(
"error writing block receipts:"
,
err
)
}
}
b
.
ResetTimer
()
filter
:=
New
(
db
)
...
...
@@ -118,47 +117,47 @@ func TestFilters(t *testing.T) {
defer
db
.
Close
()
genesis
:=
core
.
WriteGenesisBlockForTesting
(
db
,
core
.
GenesisAccount
{
addr
,
big
.
NewInt
(
1000000
)})
chain
:=
core
.
GenerateChain
(
genesis
,
db
,
1000
,
func
(
i
int
,
gen
*
core
.
BlockGen
)
{
chain
,
receipts
:=
core
.
GenerateChain
(
genesis
,
db
,
1000
,
func
(
i
int
,
gen
*
core
.
BlockGen
)
{
var
receipts
types
.
Receipts
switch
i
{
case
1
:
receipt
:=
types
.
NewReceipt
(
nil
,
new
(
big
.
Int
))
receipt
.
SetLogs
(
vm
.
Logs
{
receipt
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
addr
,
Topics
:
[]
common
.
Hash
{
hash1
},
},
}
)
}
gen
.
AddUncheckedReceipt
(
receipt
)
receipts
=
types
.
Receipts
{
receipt
}
case
2
:
receipt
:=
types
.
NewReceipt
(
nil
,
new
(
big
.
Int
))
receipt
.
SetLogs
(
vm
.
Logs
{
receipt
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
addr
,
Topics
:
[]
common
.
Hash
{
hash2
},
},
}
)
}
gen
.
AddUncheckedReceipt
(
receipt
)
receipts
=
types
.
Receipts
{
receipt
}
case
998
:
receipt
:=
types
.
NewReceipt
(
nil
,
new
(
big
.
Int
))
receipt
.
SetLogs
(
vm
.
Logs
{
receipt
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
addr
,
Topics
:
[]
common
.
Hash
{
hash3
},
},
}
)
}
gen
.
AddUncheckedReceipt
(
receipt
)
receipts
=
types
.
Receipts
{
receipt
}
case
999
:
receipt
:=
types
.
NewReceipt
(
nil
,
new
(
big
.
Int
))
receipt
.
SetLogs
(
vm
.
Logs
{
receipt
.
Logs
=
vm
.
Logs
{
&
vm
.
Log
{
Address
:
addr
,
Topics
:
[]
common
.
Hash
{
hash4
},
},
}
)
}
gen
.
AddUncheckedReceipt
(
receipt
)
receipts
=
types
.
Receipts
{
receipt
}
}
...
...
@@ -173,7 +172,7 @@ func TestFilters(t *testing.T) {
// by one
core
.
WriteMipmapBloom
(
db
,
uint64
(
i
+
1
),
receipts
)
})
for
_
,
block
:=
range
chain
{
for
i
,
block
:=
range
chain
{
core
.
WriteBlock
(
db
,
block
)
if
err
:=
core
.
WriteCanonicalHash
(
db
,
block
.
Hash
(),
block
.
NumberU64
());
err
!=
nil
{
t
.
Fatalf
(
"failed to insert block number: %v"
,
err
)
...
...
@@ -181,7 +180,7 @@ func TestFilters(t *testing.T) {
if
err
:=
core
.
WriteHeadBlockHash
(
db
,
block
.
Hash
());
err
!=
nil
{
t
.
Fatalf
(
"failed to insert block number: %v"
,
err
)
}
if
err
:=
core
.
PutBlockReceipts
(
db
,
block
,
block
.
Receipts
()
);
err
!=
nil
{
if
err
:=
core
.
PutBlockReceipts
(
db
,
block
.
Hash
(),
receipts
[
i
]
);
err
!=
nil
{
t
.
Fatal
(
"error writing block receipts:"
,
err
)
}
}
...
...
eth/handler.go
浏览文件 @
5b0ee8ec
...
...
@@ -84,6 +84,11 @@ type ProtocolManager struct {
// NewProtocolManager returns a new ethereum sub protocol manager. The Ethereum sub protocol manages peers capable
// with the ethereum network.
func
NewProtocolManager
(
fastSync
bool
,
networkId
int
,
mux
*
event
.
TypeMux
,
txpool
txPool
,
pow
pow
.
PoW
,
blockchain
*
core
.
BlockChain
,
chaindb
ethdb
.
Database
)
(
*
ProtocolManager
,
error
)
{
// Figure out whether to allow fast sync or not
if
fastSync
&&
blockchain
.
CurrentBlock
()
.
NumberU64
()
>
0
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"blockchain not empty, fast sync disabled"
)
fastSync
=
false
}
// Create the protocol manager with the base fields
manager
:=
&
ProtocolManager
{
fastSync
:
fastSync
,
...
...
@@ -103,7 +108,7 @@ func NewProtocolManager(fastSync bool, networkId int, mux *event.TypeMux, txpool
if
fastSync
&&
version
<
eth63
{
continue
}
// Compatible
, initializ
e the sub-protocol
// Compatible
; initialis
e the sub-protocol
version
:=
version
// Closure for the run
manager
.
SubProtocols
=
append
(
manager
.
SubProtocols
,
p2p
.
Protocol
{
Name
:
"eth"
,
...
...
@@ -120,13 +125,9 @@ func NewProtocolManager(fastSync bool, networkId int, mux *event.TypeMux, txpool
return
nil
,
errIncompatibleConfig
}
// Construct the different synchronisation mechanisms
syncMode
:=
downloader
.
FullSync
if
fastSync
{
syncMode
=
downloader
.
FastSync
}
manager
.
downloader
=
downloader
.
New
(
syncMode
,
chaindb
,
manager
.
eventMux
,
blockchain
.
HasHeader
,
blockchain
.
HasBlock
,
blockchain
.
GetHeader
,
blockchain
.
GetBlock
,
blockchain
.
CurrentHeader
,
blockchain
.
CurrentBlock
,
blockchain
.
CurrentFastBlock
,
blockchain
.
FastSyncCommitHead
,
blockchain
.
GetTd
,
blockchain
.
InsertHeaderChain
,
blockchain
.
InsertChain
,
blockchain
.
InsertReceiptChain
,
blockchain
.
Rollback
,
manager
.
removePeer
)
manager
.
downloader
=
downloader
.
New
(
chaindb
,
manager
.
eventMux
,
blockchain
.
HasHeader
,
blockchain
.
HasBlock
,
blockchain
.
GetHeader
,
blockchain
.
GetBlock
,
blockchain
.
CurrentHeader
,
blockchain
.
CurrentBlock
,
blockchain
.
CurrentFastBlock
,
blockchain
.
FastSyncCommitHead
,
blockchain
.
GetTd
,
blockchain
.
InsertHeaderChain
,
blockchain
.
InsertChain
,
blockchain
.
InsertReceiptChain
,
blockchain
.
Rollback
,
manager
.
removePeer
)
validator
:=
func
(
block
*
types
.
Block
,
parent
*
types
.
Block
)
error
{
return
core
.
ValidateHeader
(
pow
,
block
.
Header
(),
parent
.
Header
(),
true
,
false
)
...
...
eth/handler_test.go
浏览文件 @
5b0ee8ec
...
...
@@ -443,7 +443,9 @@ func testGetNodeData(t *testing.T, protocol int) {
// Fetch for now the entire chain db
hashes
:=
[]
common
.
Hash
{}
for
_
,
key
:=
range
pm
.
chaindb
.
(
*
ethdb
.
MemDatabase
)
.
Keys
()
{
hashes
=
append
(
hashes
,
common
.
BytesToHash
(
key
))
if
len
(
key
)
==
len
(
common
.
Hash
{})
{
hashes
=
append
(
hashes
,
common
.
BytesToHash
(
key
))
}
}
p2p
.
Send
(
peer
.
app
,
0x0d
,
hashes
)
msg
,
err
:=
peer
.
app
.
ReadMsg
()
...
...
eth/metrics.go
浏览文件 @
5b0ee8ec
...
...
@@ -101,7 +101,7 @@ func (rw *meteredMsgReadWriter) ReadMsg() (p2p.Msg, error) {
packets
,
traffic
=
reqBlockInPacketsMeter
,
reqBlockInTrafficMeter
case
rw
.
version
>=
eth62
&&
msg
.
Code
==
BlockHeadersMsg
:
packets
,
traffic
=
req
BlockInPacketsMeter
,
reqBlock
InTrafficMeter
packets
,
traffic
=
req
HeaderInPacketsMeter
,
reqHeader
InTrafficMeter
case
rw
.
version
>=
eth62
&&
msg
.
Code
==
BlockBodiesMsg
:
packets
,
traffic
=
reqBodyInPacketsMeter
,
reqBodyInTrafficMeter
...
...
eth/sync.go
浏览文件 @
5b0ee8ec
...
...
@@ -22,6 +22,7 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/logger"
"github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/p2p/discover"
...
...
@@ -165,5 +166,20 @@ func (pm *ProtocolManager) synchronise(peer *peer) {
return
}
// Otherwise try to sync with the downloader
pm
.
downloader
.
Synchronise
(
peer
.
id
,
peer
.
Head
(),
peer
.
Td
())
mode
:=
downloader
.
FullSync
if
pm
.
fastSync
{
mode
=
downloader
.
FastSync
}
pm
.
downloader
.
Synchronise
(
peer
.
id
,
peer
.
Head
(),
peer
.
Td
(),
mode
)
// If fast sync was enabled, and we synced up, disable it
if
pm
.
fastSync
{
for
pm
.
downloader
.
Synchronising
()
{
time
.
Sleep
(
100
*
time
.
Millisecond
)
}
if
pm
.
blockchain
.
CurrentBlock
()
.
NumberU64
()
>
0
{
glog
.
V
(
logger
.
Info
)
.
Infof
(
"fast sync complete, auto disabling"
)
pm
.
fastSync
=
false
}
}
}
eth/sync_test.go
0 → 100644
浏览文件 @
5b0ee8ec
// Copyright 2015 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
eth
import
(
"testing"
"time"
"github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/p2p/discover"
)
// Tests that fast sync gets disabled as soon as a real block is successfully
// imported into the blockchain.
func
TestFastSyncDisabling
(
t
*
testing
.
T
)
{
// Create a pristine protocol manager, check that fast sync is left enabled
pmEmpty
:=
newTestProtocolManagerMust
(
t
,
true
,
0
,
nil
,
nil
)
if
!
pmEmpty
.
fastSync
{
t
.
Fatalf
(
"fast sync disabled on pristine blockchain"
)
}
// Create a full protocol manager, check that fast sync gets disabled
pmFull
:=
newTestProtocolManagerMust
(
t
,
true
,
1024
,
nil
,
nil
)
if
pmFull
.
fastSync
{
t
.
Fatalf
(
"fast sync not disabled on non-empty blockchain"
)
}
// Sync up the two peers
io1
,
io2
:=
p2p
.
MsgPipe
()
go
pmFull
.
handle
(
pmFull
.
newPeer
(
63
,
NetworkId
,
p2p
.
NewPeer
(
discover
.
NodeID
{},
"empty"
,
nil
),
io2
))
go
pmEmpty
.
handle
(
pmEmpty
.
newPeer
(
63
,
NetworkId
,
p2p
.
NewPeer
(
discover
.
NodeID
{},
"full"
,
nil
),
io1
))
time
.
Sleep
(
250
*
time
.
Millisecond
)
pmEmpty
.
synchronise
(
pmEmpty
.
peers
.
BestPeer
())
// Check that fast sync was disabled
if
pmEmpty
.
fastSync
{
t
.
Fatalf
(
"fast sync not disabled after successful synchronisation"
)
}
}
ethdb/memory_database.go
浏览文件 @
5b0ee8ec
...
...
@@ -17,6 +17,7 @@
package
ethdb
import
(
"errors"
"fmt"
"sync"
...
...
@@ -56,7 +57,10 @@ func (db *MemDatabase) Get(key []byte) ([]byte, error) {
db
.
lock
.
RLock
()
defer
db
.
lock
.
RUnlock
()
return
db
.
db
[
string
(
key
)],
nil
if
entry
,
ok
:=
db
.
db
[
string
(
key
)];
ok
{
return
entry
,
nil
}
return
nil
,
errors
.
New
(
"not found"
)
}
func
(
db
*
MemDatabase
)
Keys
()
[][]
byte
{
...
...
@@ -132,8 +136,8 @@ func (b *memBatch) Write() error {
b
.
lock
.
RLock
()
defer
b
.
lock
.
RUnlock
()
b
.
db
.
lock
.
R
Lock
()
defer
b
.
db
.
lock
.
R
Unlock
()
b
.
db
.
lock
.
Lock
()
defer
b
.
db
.
lock
.
Unlock
()
for
_
,
kv
:=
range
b
.
writes
{
b
.
db
.
db
[
string
(
kv
.
k
)]
=
kv
.
v
...
...
rpc/api/eth.go
浏览文件 @
5b0ee8ec
...
...
@@ -168,9 +168,7 @@ func (self *ethApi) IsMining(req *shared.Request) (interface{}, error) {
}
func
(
self
*
ethApi
)
IsSyncing
(
req
*
shared
.
Request
)
(
interface
{},
error
)
{
current
:=
self
.
ethereum
.
BlockChain
()
.
CurrentBlock
()
.
NumberU64
()
origin
,
height
:=
self
.
ethereum
.
Downloader
()
.
Boundaries
()
origin
,
current
,
height
:=
self
.
ethereum
.
Downloader
()
.
Progress
()
if
current
<
height
{
return
map
[
string
]
interface
{}{
"startingBlock"
:
newHexNum
(
big
.
NewInt
(
int64
(
origin
))
.
Bytes
()),
...
...
trie/sync.go
浏览文件 @
5b0ee8ec
...
...
@@ -31,7 +31,7 @@ type request struct {
object
*
node
// Target node to populate with retrieved data (hashnode originally)
parents
[]
*
request
// Parent state nodes referencing this entry (notify all upon completion)
depth
int
// Depth level within the trie the node is located to prioriti
z
e DFS
depth
int
// Depth level within the trie the node is located to prioriti
s
e DFS
deps
int
// Number of dependencies before allowed to commit this node
callback
TrieSyncLeafCallback
// Callback to invoke if a leaf node it reached on this branch
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录