Commit f186b390 authored by Péter Szilágyi's avatar Péter Szilágyi

eth/downloader: add fast and light sync strategies

parent c33cc382
...@@ -140,13 +140,12 @@ func GetBlockReceipts(db ethdb.Database, hash common.Hash) types.Receipts { ...@@ -140,13 +140,12 @@ func GetBlockReceipts(db ethdb.Database, hash common.Hash) types.Receipts {
if len(data) == 0 { if len(data) == 0 {
return nil return nil
} }
receipts := new(types.Receipts)
var receipts types.Receipts if err := rlp.DecodeBytes(data, receipts); err != nil {
err := rlp.DecodeBytes(data, &receipts) glog.V(logger.Error).Infof("invalid receipt array RLP for hash %x: %v", hash, err)
if err != nil { return nil
glog.V(logger.Core).Infoln("GetReceiptse err", err)
} }
return receipts return *receipts
} }
// PutBlockReceipts stores the block's transactions associated receipts // PutBlockReceipts stores the block's transactions associated receipts
......
...@@ -172,8 +172,8 @@ type storageblock struct { ...@@ -172,8 +172,8 @@ type storageblock struct {
} }
var ( var (
emptyRootHash = DeriveSha(Transactions{}) EmptyRootHash = DeriveSha(Transactions{})
emptyUncleHash = CalcUncleHash(nil) EmptyUncleHash = CalcUncleHash(nil)
) )
// NewBlock creates a new block. The input data is copied, // NewBlock creates a new block. The input data is copied,
...@@ -188,7 +188,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []* ...@@ -188,7 +188,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*
// TODO: panic if len(txs) != len(receipts) // TODO: panic if len(txs) != len(receipts)
if len(txs) == 0 { if len(txs) == 0 {
b.header.TxHash = emptyRootHash b.header.TxHash = EmptyRootHash
} else { } else {
b.header.TxHash = DeriveSha(Transactions(txs)) b.header.TxHash = DeriveSha(Transactions(txs))
b.transactions = make(Transactions, len(txs)) b.transactions = make(Transactions, len(txs))
...@@ -196,7 +196,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []* ...@@ -196,7 +196,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*
} }
if len(receipts) == 0 { if len(receipts) == 0 {
b.header.ReceiptHash = emptyRootHash b.header.ReceiptHash = EmptyRootHash
} else { } else {
b.header.ReceiptHash = DeriveSha(Receipts(receipts)) b.header.ReceiptHash = DeriveSha(Receipts(receipts))
b.header.Bloom = CreateBloom(receipts) b.header.Bloom = CreateBloom(receipts)
...@@ -205,7 +205,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []* ...@@ -205,7 +205,7 @@ func NewBlock(header *Header, txs []*Transaction, uncles []*Header, receipts []*
} }
if len(uncles) == 0 { if len(uncles) == 0 {
b.header.UncleHash = emptyUncleHash b.header.UncleHash = EmptyUncleHash
} else { } else {
b.header.UncleHash = CalcUncleHash(uncles) b.header.UncleHash = CalcUncleHash(uncles)
b.uncles = make([]*Header, len(uncles)) b.uncles = make([]*Header, len(uncles))
......
This diff is collapsed.
This diff is collapsed.
...@@ -42,4 +42,9 @@ var ( ...@@ -42,4 +42,9 @@ var (
bodyReqTimer = metrics.NewTimer("eth/downloader/bodies/req") bodyReqTimer = metrics.NewTimer("eth/downloader/bodies/req")
bodyDropMeter = metrics.NewMeter("eth/downloader/bodies/drop") bodyDropMeter = metrics.NewMeter("eth/downloader/bodies/drop")
bodyTimeoutMeter = metrics.NewMeter("eth/downloader/bodies/timeout") bodyTimeoutMeter = metrics.NewMeter("eth/downloader/bodies/timeout")
receiptInMeter = metrics.NewMeter("eth/downloader/receipts/in")
receiptReqTimer = metrics.NewTimer("eth/downloader/receipts/req")
receiptDropMeter = metrics.NewMeter("eth/downloader/receipts/drop")
receiptTimeoutMeter = metrics.NewMeter("eth/downloader/receipts/timeout")
) )
// 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 downloader
// SyncMode represents the synchronisation mode of the downloader.
type SyncMode int
const (
FullSync SyncMode = iota // Synchronise the entire block-chain history from full blocks
FastSync // Quikcly download the headers, full sync only at the chain head
LightSync // Download only the headers and terminate afterwards
)
This diff is collapsed.
This diff is collapsed.
...@@ -120,15 +120,25 @@ func NewProtocolManager(mode Mode, networkId int, mux *event.TypeMux, txpool txP ...@@ -120,15 +120,25 @@ func NewProtocolManager(mode Mode, networkId int, mux *event.TypeMux, txpool txP
return nil, errIncompatibleConfig return nil, errIncompatibleConfig
} }
// Construct the different synchronisation mechanisms // Construct the different synchronisation mechanisms
manager.downloader = downloader.New(manager.eventMux, manager.blockchain.HasBlock, manager.blockchain.GetBlock, manager.blockchain.CurrentBlock, manager.blockchain.GetTd, manager.blockchain.InsertChain, manager.removePeer) var syncMode downloader.SyncMode
switch mode {
case ArchiveMode:
syncMode = downloader.FullSync
case FullMode:
syncMode = downloader.FastSync
case LightMode:
syncMode = downloader.LightSync
}
manager.downloader = downloader.New(syncMode, manager.eventMux, blockchain.HasHeader, blockchain.HasBlock, blockchain.GetHeader, blockchain.GetBlock,
blockchain.CurrentHeader, blockchain.CurrentBlock, blockchain.GetTd, blockchain.InsertHeaderChain, blockchain.InsertChain, nil, manager.removePeer)
validator := func(block *types.Block, parent *types.Block) error { validator := func(block *types.Block, parent *types.Block) error {
return core.ValidateHeader(pow, block.Header(), parent.Header(), true, false) return core.ValidateHeader(pow, block.Header(), parent.Header(), true, false)
} }
heighter := func() uint64 { heighter := func() uint64 {
return manager.blockchain.CurrentBlock().NumberU64() return blockchain.CurrentBlock().NumberU64()
} }
manager.fetcher = fetcher.New(manager.blockchain.GetBlock, validator, manager.BroadcastBlock, heighter, manager.blockchain.InsertChain, manager.removePeer) manager.fetcher = fetcher.New(blockchain.GetBlock, validator, manager.BroadcastBlock, heighter, blockchain.InsertChain, manager.removePeer)
return manager, nil return manager, nil
} }
...@@ -210,7 +220,7 @@ func (pm *ProtocolManager) handle(p *peer) error { ...@@ -210,7 +220,7 @@ func (pm *ProtocolManager) handle(p *peer) error {
// Register the peer in the downloader. If the downloader considers it banned, we disconnect // Register the peer in the downloader. If the downloader considers it banned, we disconnect
if err := pm.downloader.RegisterPeer(p.id, p.version, p.Head(), if err := pm.downloader.RegisterPeer(p.id, p.version, p.Head(),
p.RequestHashes, p.RequestHashesFromNumber, p.RequestBlocks, p.RequestHashes, p.RequestHashesFromNumber, p.RequestBlocks,
p.RequestHeadersByHash, p.RequestHeadersByNumber, p.RequestBodies); err != nil { p.RequestHeadersByHash, p.RequestHeadersByNumber, p.RequestBodies, p.RequestReceipts); err != nil {
return err return err
} }
// Propagate existing transactions. new transactions appearing // Propagate existing transactions. new transactions appearing
...@@ -514,22 +524,31 @@ func (pm *ProtocolManager) handleMsg(p *peer) error { ...@@ -514,22 +524,31 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
var ( var (
hash common.Hash hash common.Hash
bytes int bytes int
receipts []*types.Receipt receipts []rlp.RawValue
) )
for bytes < softResponseLimit && len(receipts) < downloader.MaxReceiptsFetch { for bytes < softResponseLimit && len(receipts) < downloader.MaxReceiptFetch {
// Retrieve the hash of the next transaction receipt // Retrieve the hash of the next block
if err := msgStream.Decode(&hash); err == rlp.EOL { if err := msgStream.Decode(&hash); err == rlp.EOL {
break break
} else if err != nil { } else if err != nil {
return errResp(ErrDecode, "msg %v: %v", msg, err) return errResp(ErrDecode, "msg %v: %v", msg, err)
} }
// Retrieve the requested receipt, stopping if enough was found // Retrieve the requested block's receipts, skipping if unknown to us
if receipt := core.GetReceipt(pm.chaindb, hash); receipt != nil { results := core.GetBlockReceipts(pm.chaindb, hash)
receipts = append(receipts, receipt) if results == nil {
bytes += len(receipt.RlpEncode()) if header := pm.blockchain.GetHeader(hash); header == nil || header.ReceiptHash != types.EmptyRootHash {
continue
}
}
// If known, encode and queue for response packet
if encoded, err := rlp.EncodeToBytes(results); err != nil {
glog.V(logger.Error).Infof("failed to encode receipt: %v", err)
} else {
receipts = append(receipts, encoded)
bytes += len(encoded)
} }
} }
return p.SendReceipts(receipts) return p.SendReceiptsRLP(receipts)
case msg.Code == NewBlockHashesMsg: case msg.Code == NewBlockHashesMsg:
// Retrieve and deseralize the remote new block hashes notification // Retrieve and deseralize the remote new block hashes notification
......
...@@ -535,15 +535,12 @@ func testGetReceipt(t *testing.T, protocol int) { ...@@ -535,15 +535,12 @@ func testGetReceipt(t *testing.T, protocol int) {
defer peer.close() defer peer.close()
// Collect the hashes to request, and the response to expect // Collect the hashes to request, and the response to expect
hashes := []common.Hash{} hashes, receipts := []common.Hash{}, []types.Receipts{}
for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ { for i := uint64(0); i <= pm.blockchain.CurrentBlock().NumberU64(); i++ {
for _, tx := range pm.blockchain.GetBlockByNumber(i).Transactions() { block := pm.blockchain.GetBlockByNumber(i)
hashes = append(hashes, tx.Hash())
} hashes = append(hashes, block.Hash())
} receipts = append(receipts, core.GetBlockReceipts(pm.chaindb, block.Hash()))
receipts := make([]*types.Receipt, len(hashes))
for i, hash := range hashes {
receipts[i] = core.GetReceipt(pm.chaindb, hash)
} }
// Send the hash request and verify the response // Send the hash request and verify the response
p2p.Send(peer.app, 0x0f, hashes) p2p.Send(peer.app, 0x0f, hashes)
......
...@@ -197,9 +197,9 @@ func (p *peer) SendNodeData(data [][]byte) error { ...@@ -197,9 +197,9 @@ func (p *peer) SendNodeData(data [][]byte) error {
return p2p.Send(p.rw, NodeDataMsg, data) return p2p.Send(p.rw, NodeDataMsg, data)
} }
// SendReceipts sends a batch of transaction receipts, corresponding to the ones // SendReceiptsRLP sends a batch of transaction receipts, corresponding to the
// requested. // ones requested from an already RLP encoded format.
func (p *peer) SendReceipts(receipts []*types.Receipt) error { func (p *peer) SendReceiptsRLP(receipts []rlp.RawValue) error {
return p2p.Send(p.rw, ReceiptsMsg, receipts) return p2p.Send(p.rw, ReceiptsMsg, receipts)
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment