diff --git a/cmd/geth/main.go b/cmd/geth/main.go index 77c04ff361..0d9f733de2 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -31,8 +31,10 @@ import ( "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/cmd/utils" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/console" "github.com/ethereum/go-ethereum/eth" + "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/internal/debug" "github.com/ethereum/go-ethereum/log" @@ -87,6 +89,7 @@ var ( utils.ULCTrustedNodesFlag, utils.ULCMinTrustedFractionFlag, utils.SyncModeFlag, + utils.ExitWhenSyncedFlag, utils.GCModeFlag, utils.LightServFlag, utils.LightPeersFlag, @@ -339,6 +342,32 @@ func startNode(ctx *cli.Context, stack *node.Node) { } } }() + + // Spawn a standalone goroutine for status synchronization monitoring, + // close the node when synchronization is complete if user required. + if ctx.GlobalBool(utils.ExitWhenSyncedFlag.Name) { + go func() { + sub := stack.EventMux().Subscribe(downloader.DoneEvent{}) + defer sub.Unsubscribe() + for { + event := <-sub.Chan() + if event == nil { + continue + } + done, ok := event.Data.(downloader.DoneEvent) + if !ok { + continue + } + if timestamp := time.Unix(done.Latest.Time.Int64(), 0); time.Since(timestamp) < 10*time.Minute { + log.Info("Synchronisation completed", "latestnum", done.Latest.Number, "latesthash", done.Latest.Hash(), + "age", common.PrettyAge(timestamp)) + stack.Stop() + } + + } + }() + } + // Start auxiliary services if enabled if ctx.GlobalBool(utils.MiningEnabledFlag.Name) || ctx.GlobalBool(utils.DeveloperFlag.Name) { // Mining only makes sense if a full Ethereum node is running diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index de2a3d0731..a19ad1094c 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -75,6 +75,7 @@ var AppHelpFlagGroups = []flagGroup{ utils.TestnetFlag, utils.RinkebyFlag, utils.SyncModeFlag, + utils.ExitWhenSyncedFlag, utils.GCModeFlag, utils.EthStatsURLFlag, utils.IdentityFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 3109bf962a..1d8c7f3786 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -162,6 +162,10 @@ var ( Usage: "Document Root for HTTPClient file scheme", Value: DirectoryString{homeDir()}, } + ExitWhenSyncedFlag = cli.BoolFlag{ + Name: "exitwhensynced", + Usage: "Exists syncing after block synchronisation", + } ULCModeConfigFlag = cli.StringFlag{ Name: "ulc.config", Usage: "Config file to use for ultra light client mode", @@ -178,7 +182,6 @@ var ( Name: "ulc.trusted", Usage: "List of trusted ULC servers", } - defaultSyncMode = eth.DefaultConfig.SyncMode SyncModeFlag = TextMarshalerFlag{ Name: "syncmode", diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 4db689f73b..58d19254c2 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -415,7 +415,8 @@ func (d *Downloader) syncWithPeer(p *peerConnection, hash common.Hash, td *big.I if err != nil { d.mux.Post(FailedEvent{err}) } else { - d.mux.Post(DoneEvent{}) + latest := d.lightchain.CurrentHeader() + d.mux.Post(DoneEvent{latest}) } }() if p.version < 62 { @@ -1369,7 +1370,6 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er } // Otherwise split the chunk of headers into batches and process them gotHeaders = true - for len(headers) > 0 { // Terminate if something failed in between processing chunks select { @@ -1432,7 +1432,6 @@ func (d *Downloader) processHeaders(origin uint64, pivot uint64, td *big.Int) er headers = headers[limit:] origin += uint64(limit) } - // Update the highest block number we know if a higher one is found. d.syncStatsLock.Lock() if d.syncStatsChainHeight < origin { diff --git a/eth/downloader/events.go b/eth/downloader/events.go index 64905b8f2a..25255a3a72 100644 --- a/eth/downloader/events.go +++ b/eth/downloader/events.go @@ -16,6 +16,10 @@ package downloader -type DoneEvent struct{} +import "github.com/ethereum/go-ethereum/core/types" + +type DoneEvent struct { + Latest *types.Header +} type StartEvent struct{} type FailedEvent struct{ Err error }