mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
eth/downloader: initialize fast sync bloom on startup
This commit is contained in:
parent
a01dc8c4d1
commit
8639d929d1
6 changed files with 50 additions and 35 deletions
|
|
@ -35,6 +35,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/eth/downloader"
|
"github.com/ethereum/go-ethereum/eth/downloader"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"gopkg.in/urfave/cli.v1"
|
"gopkg.in/urfave/cli.v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -375,8 +376,13 @@ func copyDb(ctx *cli.Context) error {
|
||||||
defer stack.Close()
|
defer stack.Close()
|
||||||
|
|
||||||
chain, chainDb := utils.MakeChain(ctx, stack)
|
chain, chainDb := utils.MakeChain(ctx, stack)
|
||||||
syncmode := *utils.GlobalTextMarshaler(ctx, utils.SyncModeFlag.Name).(*downloader.SyncMode)
|
syncMode := *utils.GlobalTextMarshaler(ctx, utils.SyncModeFlag.Name).(*downloader.SyncMode)
|
||||||
dl := downloader.New(syncmode, 0, chainDb, uint64(ctx.GlobalInt(utils.CacheFlag.Name)/2), new(event.TypeMux), chain, nil, nil)
|
|
||||||
|
var syncBloom *trie.SyncBloom
|
||||||
|
if syncMode == downloader.FastSync {
|
||||||
|
syncBloom = trie.NewSyncBloom(uint64(ctx.GlobalInt(utils.CacheFlag.Name)/2), chainDb)
|
||||||
|
}
|
||||||
|
dl := downloader.New(0, chainDb, syncBloom, new(event.TypeMux), chain, nil, nil)
|
||||||
|
|
||||||
// Create a source peer to satisfy downloader requests from
|
// Create a source peer to satisfy downloader requests from
|
||||||
db, err := rawdb.NewLevelDBDatabase(ctx.Args().First(), ctx.GlobalInt(utils.CacheFlag.Name)/2, 256, "")
|
db, err := rawdb.NewLevelDBDatabase(ctx.Args().First(), ctx.GlobalInt(utils.CacheFlag.Name)/2, 256, "")
|
||||||
|
|
@ -395,7 +401,7 @@ func copyDb(ctx *cli.Context) error {
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
|
|
||||||
currentHeader := hc.CurrentHeader()
|
currentHeader := hc.CurrentHeader()
|
||||||
if err = dl.Synchronise("local", currentHeader.Hash(), hc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64()), syncmode); err != nil {
|
if err = dl.Synchronise("local", currentHeader.Hash(), hc.GetTd(currentHeader.Hash(), currentHeader.Number.Uint64()), syncMode); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for dl.Synchronising() {
|
for dl.Synchronising() {
|
||||||
|
|
|
||||||
|
|
@ -106,9 +106,8 @@ type Downloader struct {
|
||||||
queue *queue // Scheduler for selecting the hashes to download
|
queue *queue // Scheduler for selecting the hashes to download
|
||||||
peers *peerSet // Set of active peers from which download can proceed
|
peers *peerSet // Set of active peers from which download can proceed
|
||||||
|
|
||||||
stateDatabase ethdb.Database // Database to state sync into (and deduplicate via)
|
stateDB ethdb.Database // Database to state sync into (and deduplicate via)
|
||||||
stateBloomSize uint64 // Number of bytes (in MB) to allocate for the bloom
|
stateBloom *trie.SyncBloom // Bloom filter for fast trie node existence checks
|
||||||
stateBloom *trie.SyncBloom // Bloom filter for fast trie node existence checks
|
|
||||||
|
|
||||||
rttEstimate uint64 // Round trip time to target for download requests
|
rttEstimate uint64 // Round trip time to target for download requests
|
||||||
rttConfidence uint64 // Confidence in the estimated RTT (unit: millionths to allow atomic ops)
|
rttConfidence uint64 // Confidence in the estimated RTT (unit: millionths to allow atomic ops)
|
||||||
|
|
@ -211,14 +210,13 @@ type BlockChain interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a new downloader to fetch hashes and blocks from remote peers.
|
// New creates a new downloader to fetch hashes and blocks from remote peers.
|
||||||
func New(mode SyncMode, checkpoint uint64, stateDb ethdb.Database, stateBloomSize uint64, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn) *Downloader {
|
func New(checkpoint uint64, stateDb ethdb.Database, stateBloom *trie.SyncBloom, mux *event.TypeMux, chain BlockChain, lightchain LightChain, dropPeer peerDropFn) *Downloader {
|
||||||
if lightchain == nil {
|
if lightchain == nil {
|
||||||
lightchain = chain
|
lightchain = chain
|
||||||
}
|
}
|
||||||
dl := &Downloader{
|
dl := &Downloader{
|
||||||
mode: mode,
|
stateDB: stateDb,
|
||||||
stateDatabase: stateDb,
|
stateBloom: stateBloom,
|
||||||
stateBloomSize: stateBloomSize,
|
|
||||||
mux: mux,
|
mux: mux,
|
||||||
checkpoint: checkpoint,
|
checkpoint: checkpoint,
|
||||||
queue: newQueue(),
|
queue: newQueue(),
|
||||||
|
|
@ -260,13 +258,15 @@ func (d *Downloader) Progress() ethereum.SyncProgress {
|
||||||
defer d.syncStatsLock.RUnlock()
|
defer d.syncStatsLock.RUnlock()
|
||||||
|
|
||||||
current := uint64(0)
|
current := uint64(0)
|
||||||
switch d.mode {
|
switch {
|
||||||
case FullSync:
|
case d.blockchain != nil && d.mode == FullSync:
|
||||||
current = d.blockchain.CurrentBlock().NumberU64()
|
current = d.blockchain.CurrentBlock().NumberU64()
|
||||||
case FastSync:
|
case d.blockchain != nil && d.mode == FastSync:
|
||||||
current = d.blockchain.CurrentFastBlock().NumberU64()
|
current = d.blockchain.CurrentFastBlock().NumberU64()
|
||||||
case LightSync:
|
case d.lightchain != nil:
|
||||||
current = d.lightchain.CurrentHeader().Number.Uint64()
|
current = d.lightchain.CurrentHeader().Number.Uint64()
|
||||||
|
default:
|
||||||
|
log.Error("Unknown downloader chain/mode combo", "light", d.lightchain != nil, "full", d.blockchain != nil, "mode", d.mode)
|
||||||
}
|
}
|
||||||
return ethereum.SyncProgress{
|
return ethereum.SyncProgress{
|
||||||
StartingBlock: d.syncStatsChainOrigin,
|
StartingBlock: d.syncStatsChainOrigin,
|
||||||
|
|
@ -368,6 +368,12 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td *big.Int, mode
|
||||||
if atomic.CompareAndSwapInt32(&d.notified, 0, 1) {
|
if atomic.CompareAndSwapInt32(&d.notified, 0, 1) {
|
||||||
log.Info("Block synchronisation started")
|
log.Info("Block synchronisation started")
|
||||||
}
|
}
|
||||||
|
// If we are already full syncing, but have a fast-sync bloom filter laying
|
||||||
|
// around, make sure it does't use memory any more. This is a special case
|
||||||
|
// when the user attempts to fast sync a new empty network.
|
||||||
|
if mode == FullSync && d.stateBloom != nil {
|
||||||
|
d.stateBloom.Close()
|
||||||
|
}
|
||||||
// Reset the queue, peer set and wake channels to clean any internal leftover state
|
// Reset the queue, peer set and wake channels to clean any internal leftover state
|
||||||
d.queue.Reset()
|
d.queue.Reset()
|
||||||
d.peers.Reset()
|
d.peers.Reset()
|
||||||
|
|
@ -1677,7 +1683,11 @@ func (d *Downloader) commitPivotBlock(result *fetchResult) error {
|
||||||
}
|
}
|
||||||
atomic.StoreInt32(&d.committed, 1)
|
atomic.StoreInt32(&d.committed, 1)
|
||||||
|
|
||||||
// If we had a bloom filter for the state sync, deallocate it now
|
// If we had a bloom filter for the state sync, deallocate it now. Note, we only
|
||||||
|
// deallocate internally, but keep the empty wrapper. This ensures that if we do
|
||||||
|
// a rollback after committing the pivot and restarting fast sync, we don't end
|
||||||
|
// up using a nil bloom. Empty bloom is fine, it just returns that it does not
|
||||||
|
// have the info we need, so reach down to the database instead.
|
||||||
if d.stateBloom != nil {
|
if d.stateBloom != nil {
|
||||||
d.stateBloom.Close()
|
d.stateBloom.Close()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -75,7 +75,7 @@ func newTester() *downloadTester {
|
||||||
tester.stateDb = rawdb.NewMemoryDatabase()
|
tester.stateDb = rawdb.NewMemoryDatabase()
|
||||||
tester.stateDb.Put(testGenesis.Root().Bytes(), []byte{0x00})
|
tester.stateDb.Put(testGenesis.Root().Bytes(), []byte{0x00})
|
||||||
|
|
||||||
tester.downloader = New(FullSync, 0, tester.stateDb, 1, new(event.TypeMux), tester, nil, tester.dropPeer)
|
tester.downloader = New(0, tester.stateDb, trie.NewSyncBloom(1, tester.stateDb), new(event.TypeMux), tester, nil, tester.dropPeer)
|
||||||
return tester
|
return tester
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,12 +59,6 @@ type stateSyncStats struct {
|
||||||
|
|
||||||
// syncState starts downloading state with the given root hash.
|
// syncState starts downloading state with the given root hash.
|
||||||
func (d *Downloader) syncState(root common.Hash) *stateSync {
|
func (d *Downloader) syncState(root common.Hash) *stateSync {
|
||||||
// The downloader was requested to start a state sync. If the state sync bloom
|
|
||||||
// filter was not yet initialized, create it now. This lazy creation ensures we
|
|
||||||
// only allocate if really really really needed.
|
|
||||||
if d.stateBloom == nil {
|
|
||||||
d.stateBloom = trie.NewSyncBloom(d.stateBloomSize, d.stateDatabase)
|
|
||||||
}
|
|
||||||
// Create the state sync
|
// Create the state sync
|
||||||
s := newStateSync(d, root)
|
s := newStateSync(d, root)
|
||||||
select {
|
select {
|
||||||
|
|
@ -246,7 +240,7 @@ type stateTask struct {
|
||||||
func newStateSync(d *Downloader, root common.Hash) *stateSync {
|
func newStateSync(d *Downloader, root common.Hash) *stateSync {
|
||||||
return &stateSync{
|
return &stateSync{
|
||||||
d: d,
|
d: d,
|
||||||
sched: state.NewStateSync(root, d.stateDatabase, d.stateBloom),
|
sched: state.NewStateSync(root, d.stateDB, d.stateBloom),
|
||||||
keccak: sha3.NewLegacyKeccak256(),
|
keccak: sha3.NewLegacyKeccak256(),
|
||||||
tasks: make(map[common.Hash]*stateTask),
|
tasks: make(map[common.Hash]*stateTask),
|
||||||
deliver: make(chan *stateReq),
|
deliver: make(chan *stateReq),
|
||||||
|
|
@ -342,7 +336,7 @@ func (s *stateSync) commit(force bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
start := time.Now()
|
start := time.Now()
|
||||||
b := s.d.stateDatabase.NewBatch()
|
b := s.d.stateDB.NewBatch()
|
||||||
if written, err := s.sched.Commit(b); written == 0 || err != nil {
|
if written, err := s.sched.Commit(b); written == 0 || err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -489,6 +483,6 @@ func (s *stateSync) updateStats(written, duplicate, unexpected int, duration tim
|
||||||
log.Info("Imported new state entries", "count", written, "elapsed", common.PrettyDuration(duration), "processed", s.d.syncStatsState.processed, "pending", s.d.syncStatsState.pending, "retry", len(s.tasks), "duplicate", s.d.syncStatsState.duplicate, "unexpected", s.d.syncStatsState.unexpected)
|
log.Info("Imported new state entries", "count", written, "elapsed", common.PrettyDuration(duration), "processed", s.d.syncStatsState.processed, "pending", s.d.syncStatsState.pending, "retry", len(s.tasks), "duplicate", s.d.syncStatsState.duplicate, "unexpected", s.d.syncStatsState.unexpected)
|
||||||
}
|
}
|
||||||
if written > 0 {
|
if written > 0 {
|
||||||
rawdb.WriteFastTrieProgress(s.d.stateDatabase, s.d.syncStatsState.processed)
|
rawdb.WriteFastTrieProgress(s.d.stateDB, s.d.syncStatsState.processed)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -120,12 +121,8 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
|
||||||
txsyncCh: make(chan *txsync),
|
txsyncCh: make(chan *txsync),
|
||||||
quitSync: make(chan struct{}),
|
quitSync: make(chan struct{}),
|
||||||
}
|
}
|
||||||
// Figure out whether to allow fast sync or not
|
// If fast sync was requested and our database is empty, grant it
|
||||||
if mode == downloader.FastSync && blockchain.CurrentBlock().NumberU64() > 0 {
|
if mode == downloader.FastSync && blockchain.CurrentBlock().NumberU64() == 0 {
|
||||||
log.Warn("Blockchain not empty, fast sync disabled")
|
|
||||||
mode = downloader.FullSync
|
|
||||||
}
|
|
||||||
if mode == downloader.FastSync {
|
|
||||||
manager.fastSync = uint32(1)
|
manager.fastSync = uint32(1)
|
||||||
}
|
}
|
||||||
// If we have trusted checkpoints, enforce them on the chain
|
// If we have trusted checkpoints, enforce them on the chain
|
||||||
|
|
@ -137,7 +134,8 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
|
||||||
manager.SubProtocols = make([]p2p.Protocol, 0, len(ProtocolVersions))
|
manager.SubProtocols = make([]p2p.Protocol, 0, len(ProtocolVersions))
|
||||||
for i, version := range ProtocolVersions {
|
for i, version := range ProtocolVersions {
|
||||||
// Skip protocol version if incompatible with the mode of operation
|
// Skip protocol version if incompatible with the mode of operation
|
||||||
if mode == downloader.FastSync && version < eth63 {
|
// TODO(karalabe): hard-drop eth/62 from the code base
|
||||||
|
if version < eth63 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// Compatible; initialise the sub-protocol
|
// Compatible; initialise the sub-protocol
|
||||||
|
|
@ -171,9 +169,16 @@ func NewProtocolManager(config *params.ChainConfig, mode downloader.SyncMode, ne
|
||||||
if len(manager.SubProtocols) == 0 {
|
if len(manager.SubProtocols) == 0 {
|
||||||
return nil, errIncompatibleConfig
|
return nil, errIncompatibleConfig
|
||||||
}
|
}
|
||||||
// Construct the different synchronisation mechanisms
|
// Construct the downloader (long sync) and its backing state bloom if fast
|
||||||
manager.downloader = downloader.New(mode, manager.checkpointNumber, chaindb, uint64(cacheLimit), manager.eventMux, blockchain, nil, manager.removePeer)
|
// sync is requested. The downloader is responsible for deallocating the state
|
||||||
|
// bloom when it's done.
|
||||||
|
var stateBloom *trie.SyncBloom
|
||||||
|
if atomic.LoadUint32(&manager.fastSync) == 1 {
|
||||||
|
stateBloom = trie.NewSyncBloom(uint64(cacheLimit), chaindb)
|
||||||
|
}
|
||||||
|
manager.downloader = downloader.New(manager.checkpointNumber, chaindb, stateBloom, manager.eventMux, blockchain, nil, manager.removePeer)
|
||||||
|
|
||||||
|
// Construct the fetcher (short sync)
|
||||||
validator := func(header *types.Header) error {
|
validator := func(header *types.Header) error {
|
||||||
return engine.VerifyHeader(blockchain, header, true)
|
return engine.VerifyHeader(blockchain, header, true)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -179,7 +179,7 @@ func NewProtocolManager(
|
||||||
if cht, ok := params.TrustedCheckpoints[blockchain.Genesis().Hash()]; ok {
|
if cht, ok := params.TrustedCheckpoints[blockchain.Genesis().Hash()]; ok {
|
||||||
checkpoint = (cht.SectionIndex+1)*params.CHTFrequency - 1
|
checkpoint = (cht.SectionIndex+1)*params.CHTFrequency - 1
|
||||||
}
|
}
|
||||||
manager.downloader = downloader.New(downloader.LightSync, checkpoint, chainDb, 0, manager.eventMux, nil, blockchain, removePeer)
|
manager.downloader = downloader.New(checkpoint, chainDb, nil, manager.eventMux, nil, blockchain, removePeer)
|
||||||
manager.peers.notify((*downloaderPeerNotify)(manager))
|
manager.peers.notify((*downloaderPeerNotify)(manager))
|
||||||
manager.fetcher = newLightFetcher(manager)
|
manager.fetcher = newLightFetcher(manager)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue