From c0179bd4fa77f880bdaa3bfc0d95f96f1ec6a35b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=C5=81ukasz=20Magiera?= <magik6k@gmail.com>
Date: Fri, 11 Oct 2019 02:31:06 +0200
Subject: [PATCH] Periodic bootstrap

---
 cmd/lotus/daemon.go  | 29 ++++--------------------
 node/builder.go      |  1 +
 node/modules/core.go | 54 +++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 56 insertions(+), 28 deletions(-)

diff --git a/cmd/lotus/daemon.go b/cmd/lotus/daemon.go
index a65c5ae39..075de8b39 100644
--- a/cmd/lotus/daemon.go
+++ b/cmd/lotus/daemon.go
@@ -94,37 +94,16 @@ var DaemonCmd = &cli.Command{
 				}
 				return lr.SetAPIEndpoint(apima)
 			}),
+
+			node.ApplyIf(func(s *node.Settings) bool { return cctx.Bool("bootstrap") },
+				node.Override(node.BootstrapKey, modules.Bootstrap),
+			),
 		)
 		if err != nil {
 			return err
 		}
 
-		go func() {
-			if !cctx.Bool("bootstrap") {
-				return
-			}
-			err := bootstrap(ctx, api)
-			if err != nil {
-				log.Error("Bootstrap failed: ", err)
-			}
-		}()
-
 		// TODO: properly parse api endpoint (or make it a URL)
 		return serveRPC(api, stop, "127.0.0.1:"+cctx.String("api"))
 	},
 }
-
-func bootstrap(ctx context.Context, api api.FullNode) error {
-	pis, err := build.BuiltinBootstrap()
-	if err != nil {
-		return err
-	}
-
-	for _, pi := range pis {
-		if err := api.NetConnect(ctx, pi); err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
diff --git a/node/builder.go b/node/builder.go
index 67c91345c..f7f1499cc 100644
--- a/node/builder.go
+++ b/node/builder.go
@@ -70,6 +70,7 @@ const (
 
 	PstoreAddSelfKeysKey = invoke(iota)
 	StartListeningKey
+	BootstrapKey
 
 	// filecoin
 	SetGenesisKey
diff --git a/node/modules/core.go b/node/modules/core.go
index 547cf0fe1..bade468bf 100644
--- a/node/modules/core.go
+++ b/node/modules/core.go
@@ -1,15 +1,20 @@
 package modules
 
 import (
+	"context"
 	"crypto/rand"
-	"io"
-	"io/ioutil"
-
+	"github.com/filecoin-project/go-lotus/build"
+	"github.com/filecoin-project/go-lotus/node/modules/helpers"
 	"github.com/gbrlsnchs/jwt/v3"
 	logging "github.com/ipfs/go-log"
+	"github.com/libp2p/go-libp2p-core/host"
 	"github.com/libp2p/go-libp2p-core/peerstore"
 	record "github.com/libp2p/go-libp2p-record"
+	"go.uber.org/fx"
 	"golang.org/x/xerrors"
+	"io"
+	"io/ioutil"
+	"time"
 
 	"github.com/filecoin-project/go-lotus/api"
 	"github.com/filecoin-project/go-lotus/chain/types"
@@ -70,3 +75,46 @@ func APISecret(keystore types.KeyStore, lr repo.LockedRepo) (*dtypes.APIAlg, err
 
 	return (*dtypes.APIAlg)(jwt.NewHS256(key.PrivateKey)), nil
 }
+
+func Bootstrap(mctx helpers.MetricsCtx, lc fx.Lifecycle, host host.Host) {
+	ctx, cancel := context.WithCancel(mctx)
+
+	lc.Append(fx.Hook{
+		OnStart: func(_ context.Context) error {
+			go func() {
+				for {
+					sctx, cancel := context.WithTimeout(ctx, build.BlockDelay*time.Second/2)
+					<-sctx.Done()
+					cancel()
+
+					if ctx.Err() != nil {
+						return
+					}
+
+					if len(host.Network().Conns()) > 0 {
+						continue
+					}
+
+					log.Warn("No peers connected, performing automatic bootstrap")
+
+					pis, err := build.BuiltinBootstrap()
+					if err != nil {
+						log.Error("Getting bootstrap addrs: ", err)
+						return
+					}
+
+					for _, pi := range pis {
+						if err := host.Connect(ctx, pi); err != nil {
+							log.Warn("bootstrap connect failed: ", err)
+						}
+					}
+				}
+			}()
+			return nil
+		},
+		OnStop: func(_ context.Context) error {
+			cancel()
+			return nil
+		},
+	})
+}